変数が関数に渡されるとき、それは参照(borrow、&または&mutを使って)として渡されるか、移動(move、参照なし)されるかのいずれかです。
Borrow: データへの参照が渡されます。データは関数の呼び出し後も利用可能ですが、不変の参照では内容を変更できず、可変の参照では1つの活性参照のみ存在できます。
fn read_length(s: &String) -> usize { s.len() }
Move: 変数全体が関数に「移動」します。渡した後は元の変数を使用できなくなります—それは移動され、アクセスしようとするとコンパイルエラーが発生します。
fn destroy(s: String) { println!("{}", s); } // sはスコープを出ると破棄されます let s = String::from("world"); destroy(s); // sはもう使えません
これにより、二重解放やその他の所有権に関するエラーが防止されます。
移動(move)で関数に渡された後、変数を使うことはできますか?
いいえ! 値で変数を渡した後—例えば、String—元の変数は無効になります:
let s = String::from("abc"); consume(s); // sはここでは無効です println!("{}", s); // コンパイルエラー
多くの人は、コピー(Copy)のある型(例えば、i32)の動作と混同します。この場合、変数は渡された後も有効です。
ストーリー
若いプログラマーが、Stringではなく&Stringを受け取る文字列処理関数を作りました。その結果、関数呼び出し後に元の文字列が利用できなくなり、二重アップロードとメモリの追加割り当てがログサーバーで発生しました。
ストーリー
あるマイクロサービスでは、重要なリソースが異なるスレッドにmoveで渡され、その後、メインスレッドでそのリソースにアクセスしようとするとコンパイルエラーが発生しました。スレッド内でリソースを参照またはArc型のラッパーを介して渡すように、アーキテクチャを緊急にリファクタリングする必要がありました。
ストーリー
内部イベントパーサーでは、データ処理中に変数がクロージャに迅速に取り込まれ(move)、その後、クロージャの外でアクセスしようとするとコンパイルエラーが発生しました。この問題はレビュー時にのみ発見され、ローカル関数より長く生存するデータにはborrowを必須とするスタイルが導入されました。