参照
参照を理解する
Section titled “参照を理解する”参照とは、ある値へのポインタを保持することである。 そのポインタを利用して、値を書き換えたり読み取ったりできる。
Rustでは参照周りのルールが複雑だが、それは危ない操作を防ぐために必要なものである。
参照のルールのお気持ち
Section titled “参照のルールのお気持ち”データ競合可能性の排除
Section titled “データ競合可能性の排除”データ競合が発生しうるコードのコンパイルを防ぐため、参照にはいくつかの制約がある。
具体的には以下の3つの条件を同時に満たす場合にデータ競合が発生しうる。
- 2つ以上のポインタが同じデータに同時にアクセスする。
- 少なくとも1つのポインタがデータに書き込みを行っている。
- データへのアクセスを動悸する機構が使用されていない。
ダウンリングポインタの排除
Section titled “ダウンリングポインタの排除”ダウンリングポインタとは、他人に渡されてしまった可能性のあるメモリを指すポインタのことである。 その箇所へのポインタを保持している間に、メモリを開放してしまうことで発生する。
Rustでは、ダウンリングポインタが発生しないように設計されているため、ポインタが指す値が必ず存在することが保証される。
参照のルール
Section titled “参照のルール”実装でお気持ちを実際に確認してみる
複数の可変参照の禁止
Section titled “複数の可変参照の禁止”同じスコープで同時に2つの可変参照を持つことはできない。
let mut s = String::from("hello");
let r1 = &mut s;let r2 = &mut s; // E0499
println!("{}, {}", r1, r2);
可変参照と普遍参照が同時に存在することの禁止
Section titled “可変参照と普遍参照が同時に存在することの禁止”同じスコープで可変参照と普遍参照を同時に持つことはできない。
let mut s = String::from("hello");
let r1 = &s;let r2 = &s; // 不変参照は同時に存在してOKlet r3 = &mut s; // E0502
println!("{}, {}", r1, r2);
関数を使った例
fn main() { let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // E0502
println!("The first word is {}", word);}
first_word()
関数はs
を不変で借用している。
そのあとのs.clear()
では、s
を可変参照しようとしているため、エラーになる。
clear()
の実装:
pub fn clear(&mut self) { self.vec.clear()}
宙に浮いた参照の排除
Section titled “宙に浮いた参照の排除”fn main() { let reference_to_nothing = dangle();}
// E0106fn dangle() -> &String { let s = String::from("hello");
&s}
E0106のエラーメッセージは、ライフタイムに関するものであり、まだ知らない機能である。
String
を直接返すことで解決する:
fn no_dangle() -> String { let s = String::from("hello");
s}
所有権がMoveされるので、関数を抜けたあとでも問題なく変数s
(から所有権が移ったもの)を扱える。