はじめに
こんにちは。細々とプログラミングをしているsotanengelです。
この記事は以下の記事の連載です。
他の連載記事 (詳細)
また本記事はEffective Rust(David Drysdale (著), 中田 秀基 (翻訳))を参考に作成されております。とてもいい書籍ですので興味を持った方は、ぜひ読んでみてください!
今日の内容
概要
RIIとは「Resource Acquisition Is Initialization(リソースの確保(Acquisition)と解放を変数の初期化(Initialization)と破棄に紐付ける)」という概念です。
この概念を用いることでunsafeコードにおける、メモリ管理などにも対応しやすくなります。
dropメソッドを自分で実装してみよう
問(リンク)
MyStruct{には自力で
dropすべき資源が紐づけられています。
dropメソッドの引数の型を変更することで、
drop`の挙動を実装しましょう。
コード (詳細)
struct MyStruct(i32);
trait MyTrait {
fn do_something(&self);
}
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("Doing something");
}
}
impl Drop for MyStruct {
// TODO: dropの引数が間違っています。
// 引数部分を修正して、drop実行後にはMyStructの資源にアクセスできないようにしてください。
fn drop(&self) {
println!("MyStruct is being dropped!");
// 以降にドロップ処理を書く
}
}
fn main() {
let x = MyStruct(57);
x.do_something();
// ここで明示的にdropを実行する
drop(x);
}
解答(リンク)
self
を引数の型にしてしまうと呼び出し後に、その資源にアクセスできてしまう。
そのため可変参照(&mut self
)を受け取る必要がある。
let x = MyStruct(57);
x.do_something();
x.drop()
x.0 *= 100; // 呼び出し後にMyStructの資源が使えてしまう。
コード (詳細)
#[allow(dead_code)]
struct MyStruct(i32);
trait MyTrait {
fn do_something(&self);
}
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("Doing something");
}
}
impl Drop for MyStruct {
// 引数として「self」ではなく、「&mut self」を利用するのは、通常メソッドのように呼び出さないためである。
// 仮に呼び出せてしまうと、以下のようなコードが実行できてしまう。
// # example
// x.drop()
// x.0 *= 100; // 呼び出し後にMyStructの資源が使えてしまう。
fn drop(&mut self) {
println!("MyStruct is being dropped!");
// 以降にドロップ処理を書く
}
}
fn main() {
let x = MyStruct(57);
x.do_something();
// ここで明示的にdropを実行する
drop(x);
}
さいごに
もしも本リポジトリで不備などあれば、リポジトリのissueやPRなどでご指摘いただければと思います。