rustの参照と借用を理解しよう

rust

この記事で書くこと

rustの参照と借用についての説明です。

所有権については別に記事を書いていますので、必要あればご確認ください。

参照と借用

参照とは

安全なポインタ変数のことです。ポインタ変数とは、変数のアドレスが保管されている変数です。ポインタ変数に関しては、こちらを参照。

以下のコードを例に解説して行きます。

let x = 5;
println!("x   = {}",x);
println!("&x  = {:p}",&x);

let rx = &x;
println!("rx  = {:p}",rx);
println!("&rx = {:p}",&rx);

実行結果

x   = 5
&x  = 0x16b5c9e64
rx  = 0x16b5c9e64
&rx = 0x16b5c9ef0

上記の実行結果を図にすると以下のようになります。

まず5という値が変数xに束縛されます。この値は0x16b5c9e64というアドレスにあります。rxにこのアドレスの値を束縛します。rx自体のアドレスは0x16b5c9ef0になります。

このアドレスは動作環境によって変わります。

借用とは

参照を作ることを借用と言います。この行ではrxはxの値を借用していることになります。

let rx = &x;

借用のルール

参照は安全なポインタ変数と言いましたが、これは借用のルールが定められているからです。借用のルールを破るとコンパイルできません。

借用のルールは、以下です。

不変参照をたくさんor可変参照1つ

まず、不変参照、可変参照についてです。

不変参照とは

参照元の値を変更できない参照のことです。以下のコードはコンパイルできません。これはrxが不変参照なのに値を変更しようとしたからです。借りてきたものを勝手に変更するのはやめましょう.

let x = 5;
let rx = &x;
*rx += 10; // <- not allowed

不変参照たくさん

不変参照はいくつ作ってもOKです。

let x = 5;
let rx = &x;
let rx2 = &x;
let rx3 = &x;
println!("{} {} {}", rx, rx2, rx3);

実行結果

5 5 5

可変参照とは

参照もとの値を変更できる参照のことです。借用するときにmutをつけると可変参照にすることができます。不変参照と違って値を変更することができます。参照元の変数も可変である必要があります。

let mut x = 5;
let rx = &mut x;
println!("{}",rx);
*rx += 10;
println!("{}",rx);

値を変更するときにつけた*は参照外し(デリファレンス)といいます。参照はずしについてはこちらを参照ください。

可変参照は1つだけ

同時に作れる可変参照は1つだけです。

可変参照が複数だとコンパイルできない

以下のコードは可変参照が2つになるため、コンパイルできません。

let mut x = 5;
let rx = &mut x;
let rx1 = &mut x; // not allowed 
println!("{}",rx);
*rx += 10;
println!("{}",rx);

しかし、rustのコンパイラさんは賢いので、以下のコードはコンパイルさせてくれます。実はrx1を作ったとき、rxが破棄されています。なので、rxが再び使われないなら、コードは合法です。

let mut x = 5;
let rx = &mut x;
let rx1 = &mut x; // ok
println!("{}",rx1);

rxを使ってしまった場合、コンパイルはできなくなります。

let mut x = 5;
let rx = &mut x;
let rx1 = &mut x; // not allowed 
println!("{}",rx);
可変参照1つと不変参照でもコンパイルできない

可変参照があるときは、不変参照も作ることができません。

let mut x = 5;
let rx = &mut x;
let rx1 = &x; // not allowed 
println!("{}",rx);

最後に

参照についての基本的な内容については以上です。ご意見、ご感想、指摘等あればコメントお願いします。

また、参照だけでなく、所有権についても知りたい方はこちらもご覧ください。

コメント

タイトルとURLをコピーしました