NLL (non-lexical lifetimes) について誤解していた。
次のコードは NLL のおかげで、 _y
に代入した &x
が次の行以降使われていないため、 &mut
で可変参照を生成できる。
use anyhow::Result; struct X<'a> (&'a i32); fn main() -> Result<()> { let mut x = 10; let _y = X(&x); let _z = &mut x; Ok(()) }
しかし、 X<'a>
に Drop
を実装した途端にコンパイルできなくなる。
impl<'a> Drop for X<'a> { fn drop(&mut self) { todo!() } }
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> src/main.rs:12:14 | 11 | let _y = X(&x); | -- immutable borrow occurs here 12 | let _z = &mut x; | ^^^^^^ mutable borrow occurs here 13 | Ok(()) 14 | } | - immutable borrow might be used here, when `_y` is dropped and runs the `Drop` code for type `X`
理由は以下の stackoverflow のコメントに書いてある。 NLL は借用が本当に使われている箇所を特定するだけで、コードの意味を変えるものではない。特に、変数のライフタイムは変わらないので、 Drop
トレイトを実装したデータ型を使うと、今までと同様に スコープが終了するタイミングで drop
メソッドが呼ばれる 。これによって参照 &x
が使われている範囲が伸びるので、コンパイルできなくなるのである。
rust - Will the non-lexical lifetime borrow checker release locks prematurely? - Stack Overflow