「TAURI」を使う前に、まず「Rust」の所有権を理解する

所有権の「参照」「借用」について
所有権のクローンは別のアドレスに複製を作りましたが、元の変数と同じアドレスを持ちながら元の変数から別の変数や引数に値を借りることもできます。そのためには、変数や引数を宣言する際に、元の変数のアドレスを「参照」する「&」を付けることで値を借りることができます。関数の引数に参照を取ることを「借用」と言います。
例えば、次のサンプルコードのように「good1」変数の前で「&」を付けて参照すれば、代入した後でも「good1」変数に所有権が残るため「main()」関数のスコープ内で「good1」変数が使えます。
・所有権の参照のサンプルコードfn main() { let good1 = String::from("Good"); let _good2 = &good1; println!("{}",good1); // エラーなし }
【サンプルコードの解説】
「good1」変数に"Good"という文字列を代入して宣言します。
「_good2」変数に「good1」変数を参照したアドレスを代入して宣言します。
「good1」変数の文字列をターミナルに表示します。
所有権の「参照」「借用」「関数」について
関数の引数で借用するには、変数の前で参照することを意味する「&」を付け、関数宣言時に「引数の型」の前でも参照することを意味する「&」を付けます。
図7とサンプルコードのように借用することにより、「good_str」関数内のスコープで引数が所有権を持たないため所有権がこのスコープで解放されることはなく、元の「good1」変数にはまだ所有権が残ります。
・所有権の参照・借用・関数のサンプルコードfn main() { let good1 = String::from("Good"); good_str(&good1); println!("{}",good1); // エラーなし } fn good_str(good: &String) { println!("{}",good); // エラーなし }
【サンプルコードの解説】
「good1」変数に"Good"という文字列を代入して宣言します。
「good_str」関数に「&good1」という風に変数の前に「&」を付け、関数の引数の「good: &String」という風に型の前に「&」を付けて参照できます。
「good」引数の文字列をターミナルに表示します。
「good1」変数の文字列をターミナルに表示します。
所有権の「参照」「借用」「関数」「ミュータブル」について
関数の引数で借用して関数内で値を変更する場合には、図8とサンプルコードのように変数の前で参照する「&mut」を付け、引数の型の前で参照する「&mut」を付けます。
また、ミュータブルな変数をイミュータブルに参照した後にミュータブルに変数を参照したり、ミュータブルな参照が複数あるとエラーになります。
・所有権の参照・借用・関数・ミュータブルのサンプルコードfn main() { let mut good1 = String::from("Good"); good_str(&mut good1); println!("{}",good1); // エラーなし } fn good_str(good: &mut String) { good.push('y'); }
【サンプルコードの解説】
「good1」変数に"Good"という文字列を代入してミュータブル(mut)で宣言します。
「good_str」関数に引数としてミュータブルな「good1」変数を参照して渡します。
「good」引数の後ろに"y"文字を足して"Goody"という文字列に変更します。
「good_str」関数内で変更された「good1」変数の文字列"Goody"をターミナルに表示します。
for文におけるイテレータについて
「for文」とは第3回でも解説した通り、決まった回数だけループする繰り返し処理の「制御構文」のことです。そのfor文で値を借用するには「iter()」メソッドで「イテレータ」を使います。そうすれば「v1」vec!マクロの各要素を参照するだけで、所有権はムーブされません。
次のサンプルコードのように、for文でコレクションは所有権を所有せず一時的に借りるだけで、ループ後もコレクションを再利用できます。「vec!」マクロに「iter()」関数を付けけないと所有権がfor文のスコープを出るときに解放されてしまい、ループ後に再利用できません。
・for文とイテレータのサンプルコードfn main() { let v1 = vec!["A","B","C"]; for v2 in v1.iter() { println!("{}",v2); } println!("{:?}",v1); // エラーなし }
【サンプルコードの解説】
vec!マクロの「v1」配列に"A"と"B"と"C"の文字列を代入して宣言します。
「for v2 in v1.iter()」で「v2」変数に"A"と"B"と"C"の値が順番に代入され「{}」内をループ処理します。
「iter(イテレータ)」はループごとにコレクションの要素を借用します。
「v1」配列の文字列をターミナルに表示します。
スライス型について
所有権のない別のデータ型に「スライス型」があります。文字列や配列やタプルなどの複数の要素を持つ値の中の一部、または全部を参照することもできます。例えば"Good"文字列の0~3番目未満の"Goo"文字列だけ取得する感じです。
図9とサンプルコードのように文字列変数の前に「&」を付け、変数の後に「[」と「]」で囲って要素の何番目から何番目未満までの要素か「..」で範囲を指定します。
・スライス型のサンプルコードfn main() { let good1 = String::from("Good"); let good2 = &good1[0..3]; println!("{}",good1); // エラーなし println!("{}",good2); // エラーなし }
【サンプルコードの解説】
「good1」変数に"Good"という文字列を代入して宣言します。
「good2」変数に"Good"という文字列の0~3未満の文字列"Goo"を代入して宣言します。
「good1」変数の文字列をターミナルに表示します。
「good2」変数の文字列をターミナルに表示します。
おわりに
今回は変数に所有権を与え、所有権の「ムーブ」「クローン」「コピー」「参照」「借用」の5大要素と、「所有権と関数」「イテレータでの借用」「スライス型」について解説しました。
たとえ詳細に所有権を解説しても、Rustのコードを書いていれば誰でもエラーが出ることはあるでしょうから、その度にエラーメッセージを見てデバッグしていくうちに体で所有権を理解した方が良いと思います。