リージョンとRustの返り値

Rustにおいては返り値ポインタで返すよりもそのまま返して、受け取る側でポインタで受け取るかそのまま受け取るかを指定するのが良い選択肢だ、といっています。 しかし初めて見る時にはどうしてそんなことが出来るのかわからず、びっくりしますよね。 それをRustがリージョンを使ってメモリ管理をしていると分かればどうなっているのか分かったのですこしばかり。

Rustにおいては以下のように関数が値を返す時にポインタを返すコードは好ましくなく、(というかコンパイル出来ない)

fn new_value() -> &BigStruct {
    &BigStruct{ .... }
}

let bs = new_value();

関数が返す値はスタックに載らないような大きな値でもそのまま返して、受け取り側でヒープに保存してあげるのが良いスタイルとされています。

fn new_value() -> BigStruct {
    BigStruct{ .... }
}

let bs = Box::new(new_value());

今までの言語の感覚だとRustにおいて良いとされるスタイルは大きな値を一旦スタックに載せた後でBoxによって作られたヒープ領域に確保されているように見えます。

これはリージョンについて理解すると動作が理解できます。

リージョンについては以前のブログを参照して下さい。

リージョンについて | κeenのHappy Hacκing Blog

さて、リージョンによるメモリ管理は「メモリを確保すべき場所」が先にあって、値はそこに置かれます。 特に、関数呼び出しにおいて、関数の「返り値を確保すべき場所」は関数の外から与えます。

ここまで説明したらお分りかと思いますが、Box::new(new_value());というコードはnew_value()の返り値を保存する場所としてヒープ領域を渡していて、 関数内部でそのヒープ領域にBigStructの値を書き込んでいるのです。

もやもやしていたものがスッキリしたし返り値のサイズが決まってないと関数から返せないのも分かるようになった。

Written by κeen