参照と借用
前回の続きで,所有権に絡む話。
参照と借用
まずはこのコードを出発点にしよう。
struct Person {
age: u32,
name: String,
}
fn main() {
let p1 = Person {
age: 24,
name: "Alice".to_string(),
};
println!("{} ({})", p1.name1, p.age); //Output: Alice (24)
}
毎回 println!
マクロで出力を整形するのはかったるいので,整形を行う関数を考えてみる。
こんな感じ。
struct Person {
age: u32,
name: String,
}
fn display_person(p: Person) -> String {
let mut s = p.name;
s.push_str(" (");
s.push_str(&p.age.to_string());
s.push_str(")");
s
}
fn main() {
let p1 = Person {
age: 24,
name: "Alice".to_string(),
};
println!("{}", display_person(p1)); //Output: Alice (24)
}
一見うまく行っているようだが,次の1行を足すとコンパイル・エラーになる。
fn main() {
let p1 = Person {
age: 24,
name: "Alice".to_string(),
};
println!("{}", display_person(p1));
println!("{}", p1.name); //Error: borrow of moved value: `p1`
}
これは 変数の p1
の値の所有権が display_person()
関数の引数 p
に移動したからである。
変数を引数にセットするたびに所有権が移るのは鬱陶しいので,変数の「参照」を引数にセットする。 こんな感じに書き換えてみよう。
fn display_person(p: &Person) -> String {
let mut s = p.name.clone();
s.push_str(" (");
s.push_str(&p.age.to_string());
s.push_str(")");
s
}
2行目の宣言文も変わってることに注意。 実は2行目を
fn display_person(p: &Person) -> String {
let mut s = p.name; //Error: cannot move out of `p.name` which is behind a shared reference
s.push_str(" (");
s.push_str(&p.age.to_string());
s.push_str(")");
s
}
のままにするとコンパイル・エラーになる。
引数 p
は元の変数の値を「借用」しているに過ぎないので,所有権の移動はできないのである。
ていうか,最初の display_person()
関数は引数の値を壊してたのか。
コワイコワイ(笑)
全体のコードは以下の通り。
struct Person {
age: u32,
name: String,
}
fn display_person(p: &Person) -> String {
let mut s = p.name.clone();
s.push_str(" (");
s.push_str(&p.age.to_string());
s.push_str(")");
s
}
fn main() {
let p1 = Person {
age: 24,
name: "Alice".to_string(),
};
println!("{}", display_person(&p1)); //Output: Alice (24)
println!("{}", p1.name); //Output: Alice
}
変数と参照の関係を図式化するとこんな感じだろうか。