ここで何が起こっているのですか( 遊び場 )?
struct Number {
num: i32
}
impl Number {
fn set(&mut self, new_num: i32) {
self.num = new_num;
}
fn get(&self) -> i32 {
self.num
}
}
fn main() {
let mut n = Number{ num: 0 };
n.set(n.get() + 1);
}
このエラーが発生します:
error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
--> <anon>:17:11
|
17 | n.set(n.get() + 1);
| - ^ - mutable borrow ends here
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
ただし、コードをこれに変更するだけで機能します。
fn main() {
let mut n = Number{ num: 0 };
let tmp = n.get() + 1;
n.set(tmp);
}
私には、これらはまったく同じように見えます。つまり、コンパイル中に前者が後者に変換されることを期待します。次のレベルの関数呼び出しを評価する前に、Rustすべての関数パラメーターを評価しませんか?
この行:
n.set(n.get() + 1);
脱糖されます
Number::set(&mut n, n.get() + 1);
エラーメッセージはもう少し明確になるかもしれません:
error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
--> <anon>:18:25
|
18 | Number::set(&mut n, n.get() + 1);
| - ^ - mutable borrow ends here
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
Rustは引数を左から右に評価するので、そのコードはこれと同等です:
let arg1 = &mut n;
let arg2 = n.get() + 1;
Number::set(arg1, arg2);
編集者注:このコード例は、根本的な問題を直感的に理解できるものですが、完全に正確ではありません。 expandedコードは、非字句の有効期間でも失敗しますが、originalコードがコンパイルされます。問題の完全な説明については、レビュー ボローチェッカーの元の実装のコメント
これで、何が問題なのかが明らかになるはずです。これらの最初の2行を入れ替えるとこれは修正されますが、Rustはそのような制御フロー分析を行いません。
これは最初に bug#6268 として作成されましたが、現在は RFC 2094 、 non-lexical-lifetimes に統合されています。 Rust 1.36以降を使用すると、NLLが自動的に有効になり、 コードはエラーなしでコンパイルされます 。