はじめに
『Ownership』(所有権)の概念は、Rustの大きな特徴の一つです。
3つのルールを押さえておく必要があります。
- あらゆる値は変数に所有される
- オーナーがスコープから外れたら値も解放される
- オーナーは常に1人
簡単なI/Oの例
input
は値を所有するオーナー- 文字列はヒープメモリに(コンパイル時にサイズが不明なため)
main
関数が終了した時、メモリも解放される
fn main() {
// input: オーナー
let mut input = String::new();
// 入力を待ち受ける
io::stdin().read_line(&mut input);
}
所有権の移動の例
input
は値を所有するオーナーinput2
も同じ値を参照している
このままだとmain
関数が終了した時、メモリの同一エリアを2度開放してしまうことになります。(エラー)
が、Rustはこのダブルフリーが起こらないよう、所有権が2つにならないよう勝手に移動させます。
fn main() {
let mut input = String::new();
// 所有権はinput2へ
let mut input2 = input;
// エラー: inputはもはや値への参照を持たない
io::stdin().read_line(&mut input);
}
関数の引数でも同じことが起こります。
fn main() {
let mut input = String::new();
// 所有権はfunctionの引数strへ
function(input);
// エラー: inputはもはや値への参照を持たない
io::stdin().read_line(&mut input);
}
fn function(str: String) {}
スタックの場合(コンパイル時にサイズが確定している)は参照ではなく値そのものをコピーできるので、移動は起こりません。
fn main() {
let mut input = 3;
let mut input2 = input;
// 問題ない
io::stdin().read_line(&mut input);
}
この所有権の移動に慣れないと、コンパイルが通らないのでプログラムを動かすことすらできません。