こんにちは、masm11 です。
Rust を勉強してみました。今回は Rust の特徴である「所有権」について、 チラ見したいと思います。
所有権とは
メモリ管理 (確保, 解放) は、プログラムを書く上で重要なことです。 間違えれば、メモリリークや解放後に参照してしまうなどの問題を引き起こします。 Ruby や Java であれば GC が搭載されているので問題にはなりにくいでしょう。 逆に C はメモリ管理を自前で間違えないように実施する必要があります。
Rust は GC なしでこれを行います。
let a = String::from("foo");
これで、変数 a には "foo"
が代入されます。
そして変数 a が要らなくなると、値を解放します。
let b = a;
こうすると a の値を b に移動させます。 a からはもう値を参照できません。
移動前は値を変数 a が所有していましたが、値を b に移動させたことで、 値の所有権が b に移動したのです。
値は一つの変数しか所有権を持ちません。所有権のある変数が要らなくなったら、 値は解放されます。
次に、関数を一つ定義して、呼び出します。
fn bar(s: String) { println!("{}", s); } fn main() { let a = String::from("foo"); bar(a); }
呼び出し時、"foo"
の所有権は、a から関数 bar の引数 s に移動しています。
bar から返ってきた後に a を参照することはできません。
fn bar(s: String) -> String { println!("{}", s); s } fn main() { let a = String::from("foo"); let b = bar(a); println!("{}", b); }
このように、bar から値を返して、それを b に受けることができます。
この時にも所有権は移動します。
このコードでは、"foo"
の所有権は、最初は main の a にあって、そのあと bar の引数 s に移動し、main の b に移動しています。
…………さすがに面倒ですね。やってられません。
「参照」があります。所有権をもとの変数に持たせたまま、盗み見することができます。
fn main() { let a = String::from("foo"); let b = &a; println!("{}", b); }
このコードでは、"foo"
の所有権は a にあり、そのままです。
変数 b が不要になったと同時に変数 a も不要になり、そのタイミングで "foo"
は解放されます。
もう少し複雑な例を出します。
fn main() { let mut b; { let a = String::from("foo"); b = &a; } println!("{}", b); }
b は外側のスコープに存在します。a は内側です。
"foo"
は a が所有しています。b はそれを盗み見ています。
a は内側のスコープを抜けたら解放されるはずです。
b が盗み見ているものがなくなるわけです。
どうなるのでしょう??
答え:コンパイルが通りません。
ちゃんとコンパイラが検出してるんですね。 逆に言うと、 プログラマが「うん、これは大丈夫。」と思っていても、 それがコンパイラに理解できなければダメなのです。 「所有権」や「ライフタイム」(今回は紹介していません) は、 コンパイラに理解できるようにするための機能で、 これらの機能を使って、いつ解放できるのか、それは間違っていないのか、 をしっかりコンパイラに伝える必要があるわけです。
Rust を使ってみた所感など
Rust は、Firefox 用に生まれた言語で、一般用途で使われるようになったのは最近だと思います。 そのせいか、まだまだ熟れていない面がありますね。 メソッドを探していたら Experimental とか書いてあって「おまえもか…」となることがあります。まぁ、手順は増えますが使えないことはないので、使えばいいんですけどね。
また、私は今まで多くのプログラミング言語を使ってきましたが、 Rust の「所有権」や「ライフタイム」(今回は紹介しませんでした) は難しく、 「この言語は本当に一般用途なのだろうか…?」 と疑ってしまう程です。 Twitter で Rust をべた褒めしているツイートを見ると、 老いぼれには過ぎた言語ってことなのかもしれません。
ではまた。