Rustで値のmoveが起こる場合
Rust v.0.11pre時点での情報です。
Rustにおけるムーブセマンティクス
だいたいC++のそれと同じものと理解してるんだけど、おさらいとして。 Rustの言語セマンティクスの一つに、メモリの所有権︵Ownership︶というものがある。これは﹁このメモリ領域を自身のもの所有しているものは常に一つ︵ユニーク︶になる﹂というもので、これが保証されると、特定のメモリの領域は、所有する変数ひいては所有するタスクが決定されるようになる。原則として、各タスクごとの単位でしか、その所有権の貸し借り︵borrowing︶ができないため、タスクAから他の非同期に動作するタスクBの所有するメモリ領域の変更は不可能になる。タスクAからタスクBに向けてデータを送信した場合、データの所有権ごと送信されるので、結果としてデータ競合が発生しないことが保証される︵もちろんArc<T>
とか使ったり、生ポインタを送信するみたいな抜け道はありますよ︶。
このOwnershipの概念に基づいて、変数のmutability規則が決まっていたり、borrowingの説明がなされるようになる。タスク間でデータをやりとりできる型かどうかについては、Se
nd
kindであるかどうかとかが絡んでくるんだけど、マニュアル読んだ方が速いのでリンクを貼るだけにとどめる。
もうひとつ、Rustではポインタに関しては、基本的にはshallow copyとなる。
なので、チュートリアルに載っている以下のようなコードでは、ポインタの複製にとどまる。
let xs = Cons(1, box Cons(2, box Cons(3, box Nil))); let ys = xs; // copies `Cons(u32, pointer)` shallowlyここで問題発生。 ここでコピーされたポインタ値はowning pointerのもの。即ち、そこにはownershipが存在している。だが、ポインタ値のみがコピーされたことで、所有していると見なされるオブジェクトが2つに増えてしまった。これではOwnershipの説明と矛盾する。 Rustでは、この矛盾の解消のために、ownershipを移動するということを行う。さっきのコードの例で言えば、子孫となっている
Cons
オブジェクトの所有権は、ポインタのコピーと同時にxy
からys
に対して移動︵ムーブ︶される。そして、古い方の所有者であるxy
は無効なものとして、以後、使用することはできなくなる︵コンパイルエラー!︶。
以上が、RustにおけるOwnershipと、それに基づくムーブセマンティクスの簡単な説明になる。
これらにより、セマンティクスの面では安全性が保証され、処理系の最適化という文脈では余計なメモリコピーが発生しなくなるのでうれしくなる、というわけ。
ムーブが起こる場合
それでは、ムーブが発生する場合は具体的にどういうケースなのかということになるので、リファレンスマニュアルから、一通り抜き出してみた。 Rustにおける代入などの操作で、copyではなくmoveとなる条件は以下の通り‥
●型がコピーではなくムーブの対象と指定されている場合︵代入など︶
●例としては、型が内部にowning pointer︵
Box
<T>
︶を含む
●Drop
traitを実装している
●つまり、Type kinds︵型の種類︶がDrop
になる場合。尚、Drop
kindは、制約上Send+Drop
になる.︵ムーブ対象の値を子孫方向に含む場合も同様︶
●Defaultとして、デストラクタ︵Drop::drop()
︶を実装している型、クロージャ環境、非ファーストクラスな型はコピー不可でありムーブする
●vectorが固定長である︵[int, ..10]
のように表現できる︶場合は、静的にサイズが決定できる為、ファーストクラスとなる
●一方、可変長である場合︵Vec<T>
または&[T]
を用いてのみ生成可能︶、非ファーストクラスとなる。
●return
式を用いて値を返す場合
●関数でreturn
を省略する場合には、最後の式が値を生み出す場合は、暗黙的にreturn
で返していると解釈されるので、return
を明示しようがしまいが関数の戻り値はmoveする
●ブロック式の末尾の値が返る場合も同じ様子
●ジェネリック関数においては、ジェネリックな型が不明瞭︵opaque︶である場合、引数の関数内での挙動はmoveに限定される
●︵<T: Copy>
のように︶型がCopy
kindであることが指定されていれば、copyされる
●クロージャ型がプロシージャ︵proc
︶である場合、参照する外部変数はムーブされる
●タスク間でデータをやり取りする場合
●この場合、Send
kindである必要がある