TL;DR
Rust のコンパイラの中で、参照(借用)と所有権の規則が守られているかを検査する部分。あるアイテムへの複数の不変参照か、単一の可変参照のどちらかだけを許し、両方が同時に存在することは許さない。
なぜ必要か
The Rust Programming Language によると、参照の規則をコンパイル時に検査するので、Rust はコンパイル時にデータ競合を防げる。参照先のデータが参照より先にスコープを外れないことも保証するので、ダングリング参照も起きない。Effective Rust 項目16 によると、この仕組みのおかげで、Rust のメモリ安全性は実行時のオーバーヘッドなしで保証される。
仕組み
rustc 開発ガイドによると、借用チェッカは次のことを確かめる。
- 変数は使う前に初期化されている
- 同じ値を 2 回ムーブしない
- 借用されている値をムーブしない
- 可変に借用されている場所に、その参照以外からアクセスしない
- 不変に借用されている場所を書き換えない
借用チェッカは、コンパイラの中間表現である MIR の上で動く。MIR を使うと生存期間を制御フローグラフから導けるので、参照の生存期間はスコープの末尾ではなく、最後に使われた時点までになる(ノンレキシカル生存期間)。
例
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{r1} and {r2}");
// r1 と r2 はここで最後に使われたので、可変参照を作れる
let r3 = &mut s;注意点
- 借用チェッカのエラーメッセージは、違反した箇所と理由を示してくれるので、まず読む(Effective Rust 項目15)。
Rc<RefCell<T>>を使うと借用チェッカの制約を避けられるが、借用違反が実行時の panic になり、使い方によっては循環参照を生む(スマートポインタを活用しよう)。