導入
「所有権を渡す(ムーブ)」のではなく、「ちょっと見せて(貸して)、使い終わったら返す」ができれば、前章の悩みは消えます。これが参照です。記号 & を使います。
説明
前章でムーブしてしまった関数を、参照で書き直します。
fn main() {
let s = String::from("hello");
let n = calc_length(&s); // &s =「s を貸す」。所有権はムーブしない
println!("'{s}' の長さは {n}"); // s はまだ使える!
}
fn calc_length(text: &String) -> usize { // &String =「String を借りる」型
text.len()
} // ← text はスコープを抜けるが、借りていただけなので何も解放しない
&s… 「sへの参照」を作ります。所有権は渡さず、sを貸すだけ。この行為を 借用(borrowing) と呼びます。text: &String… 関数はStringを借りている(所有していない)ことを型で表します。- 関数が終わっても、
textは借り物なのでヒープを解放しません。所有者はあくまでmainのs。だからmainに戻ってもsは健在です。
参照は「ヒープデータそのもの」ではなく「所有者を指すポインタ」だと考えるとしっくりきます。
graph LR
subgraph stack["スタック"]
text["text(&String・借用)"]
s["s(String・所有者)"]
end
subgraph heap["ヒープ"]
d["h | e | l | l | o"]
end
text -->|指す| s
s -->|所有| d
text は s を指し、s がヒープを所有する。だから借用中にヒープが勝手に解放される心配はありません(所有者 s が生きている限り、データは有効)。
このように「所有権を渡さずに値へアクセスする参照を作ること」が借用です。既定の & で作る参照は 不変(読み取り専用) で、借りた値を書き換えることはできません。書き換えたいときは次のレッスンの &mut を使います。
試すには
前章のムーブでエラーになったコードを、関数の引数を &s/&String に変えるだけで解決できます。clone() のようなコピーコストもかかりません。「渡す」を「貸す」に変えるだけ——この置き換えを体に染み込ませましょう。