LoginSignup
1
1

More than 1 year has passed since last update.

rustの所有権と参照

Last updated at Posted at 2021-08-14

Cと少し違うところがある感じがしたのでメモ。
前提として、Cでのポインタ、参照などを分かっていないと難しい。

所有権について

rustには所有権という概念がある。

String型など、ヒープによって確保されるデータ(コンパイル時にサイズが不明なデータとも言える)を変数に格納するとき、そのデータ ”そのもの” ではなく ”データのポインタ” が格納される。(Cでの文字列と同じ感じ。)

もし、下コードのように x がString型の変数であり、そこから y = x とするとき、x, yどちらも、同じ"データのポインタ"が格納される。

そして、rustはスコープを抜けたら、メモリを開放するという特徴がある。

もしx, yで同じポインタを持っているのであれば、同じメモリを解放しようとしてしまう。
これを防ぐためのものが”所有権”である。
y = x としたときに所有権がyに移る、つまりxは無効にされるのである。
なので下コードはコンパイルが通らない。

main.rs
fn mov()
{
    // 前提 rustはスコープから抜けたらメモリを開放する
    let x = String::from("hello");
    let y = x;
    // この時、”所有権”がyに渡される
    // 渡されたらxは無効となる(開放するとき、xが有効だとx, yで同じアドレスを開放することになってしまう)
    // 所有権はポインタとは違う(参照ではない)
    println!("{}, {}", x, y);
    // この場合コンパイルエラーが発生(xを指定したため)
}

ちなみにヒープで確保されないデータ(スタックで確保されるデータ、整数型など。)では、値がコピーされるので、下のコードのように

main.rs
fn cpy()
{
    let x = 5;
    let y = x;

    println!("{}, {}", x, y);
    //出力結果:5, 5
}

とすることができる。

所有権はそのままで、データを参照する

参照を使えば、所有権は移動しないで、値を見ることができる。

main.rs
fn mov()
{
    let x = String::from("hello");
    let y = &x;
    // yはxを参照する 所有権は移動しない
    println!("{}, {}", x, y);
    // 出力結果:hello, hello
    // この場合コンパイルエラーは発生しない
}

ここでは、x文字列データのポインタを持っており、yxへのポインタを持っている
つまり、二重開放にならず、エラーを吐かない。

ただし、ここでは参照なので、xの値が変化したらyも変化してしまう。
借用されているのでそもそもxの値を変化できないです(&mutとか使えば違うのかもしれないですけど)。2か月前の自分変なこと書いてる...

それが嫌なら、depp copyをすればいい。これでヒープデータが完璧にコピーされる。

main.rs
fn mov()
{    
    let x = String::from("hello");
    let y = x.clone();
    // yはxのdeep copyとなる つまりhelloという文字列がメモリ空間に二つ確保される
    println!("{}, {}", x, y);
    // 出力結果:hello, hello
}

まとめ

ヒープで確保されるデータ ... 一つのデータで、アドレスを参照することによってやりくり -> ムーブ
rustはこのようなデータはデフォルトでは一つでやりくりする?

スタックで確保されるデータ ... データを複製できる -> コピー

所有権が移る = データがムーブされるといった感じでいいのだろうか。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1