有権
理解
ヒープ上のデータでは、let b = a; 浅いコピーだけが行われ、その時で a invalid,アクセスできません(つまり move が発生します)
次のように書く必要があります let b = a.clone(); そうすれば深いコピーになり、 a アクセスできます
関数の入力引数の型を String と宣言すると浅いコピー(渡した値の moved)が起きます。一方、 reference (&String)では moved しません
(reference を作る過程を borrowing と呼びます)
reference の値を変したい場合、引数は &mut String
同じ時で同じ元データに対して
は 1 つだけ持てます &mut reference 声明(变),者
は複数持てます & reference 声明(不变)。
Rust には trait という annotation があります(詳細は後述します)
参照元
https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
…
Rust には、スタックに保存される整数のような型に付けられる Copy trait という特別な annotation があります(trait については 10 章で詳しく説明します)。型が Copy trait を実装していれば、代入後も元の変数を使できます。型またはその一部が Drop trait を実装している場合、その型に Copy trait を付けることはできません。値がスコープを抜けるときに特別な処理が必要な型へ Copy annotation を付けると、コンパイル時エラーになります。型に Copy annotation を付ける方法は、付録 C の
「導出な trait」
を参照してください。
では、どの型が Copy trait を実装するのでしょうか。正確には各型のドキュメントを確認してください。一般に、単純なスカラー値の組み合わせは Copy を実装できますが、メモリ確保が必要なものや何らかのリソースであるものは実装できません。次は Copy を実装する型の例です。
u32など、すべての整数型。trueとfalseの値を持つ Boolean 型bool。f64など、すべての浮動小数型。- 文字型
char。 Copyを実装する型だけを含むタプル。たとえば(i32, i32)はCopyを実装しますが、(i32, String)は実装しません。
…
ファイル名: src/main.rs
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
エラーは次のとおりです。
$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0499]: cannot borrow `s` as mutable more than once at a time
--> src/main.rs:5:14
|
4 | let r1 = &mut s;
| ------ first mutable borrow occurs here
5 | let r2 = &mut s;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | println!("{}, {}", r1, r2);
| -- first borrow later used here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `ownership` due to previous error
このエラーは、s を同時に 2 回以上変借できないため、このコードが無効だと示しています。最初の変借は r1 にあり、println! で使われるまで有効でなければなりません。しかし、その変 reference の作成から使までの間に、r1 と同じデータを借する別の変 reference を r2 に作ろうとしています。
…
As always, we can use curly brackets to create a new scope, allowing for multiple mutable references, just not simultaneous ones:
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1 goes out of scope here, so we can make a new reference with no problems.
let r2 = &mut s;
変 reference と不変 reference の組み合わせにも同様のルールがあります。このコードはエラーになります。
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM
println!("{}, {}, and {}", r1, r2, r3);
エラーは次のとおりです。
$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:6:14
|
4 | let r1 = &s; // no problem
| -- immutable borrow occurs here
5 | let r2 = &s; // no problem
6 | let r3 = &mut s; // BIG PROBLEM
| ^^^^^^ mutable borrow occurs here
7 |
8 | println!("{}, {}, and {}", r1, r2, r3);
| -- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` due to previous error
ふう!不変 reference がある間は、変 reference も持てません。不変 reference の利者は、読んでいる値が突然変わるとは想定していません。ただし、複数の不変 reference は問題ありません。データを読むだけの利者が、他の利者の読み取りに影響をえることはないからです。
reference のスコープは導入された場から始まり、その reference が最後に使われる場まで続きます。たとえば、次のコードは不変 reference の最後の使である println! が変 reference の導入前にあるため、コンパイルできます。
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// variables r1 and r2 will not be used after this point
let r3 = &mut s; // no problem
println!("{}", r3);
…
reference のルール
Let’s recap what we’ve discussed about references:
- At any given time, you can have either one mutable reference or any number of immutable references.
- References must always be valid.