Rust の「所有権」機能をチラ見

こんにちは、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 をべた褒めしているツイートを見ると、 老いぼれには過ぎた言語ってことなのかもしれません。

ではまた。