所有権システム(ownership)は、Rustがコンパイル時にメモリの安全性を確保するための基本概念です。各変数には所有者がいます。特定の時点でリソースの所有者は一人だけです。
所有権は、代入や関数への渡し時に移動(move)します。所有権が移動すると、以前の所有者は値を使用できなくなります:
let s = String::from("hello"); let t = s; // sはもう使用できません
Rustはまた、**借用(borrowing)**を区別します。
&T — 読み取り専用の参照(borrow)。&mut T — 可変参照(mutable borrow)、ただし同時に一つだけ存在できます。これらのルールにより、Rustはメモリ解放後に使用されるデータ競合やその他のリソース管理のエラーが発生しないことを保証します。
同じ値に対して同時に複数の可変参照(&mut T)を持つことができますか? なぜですか?
答え: いいえ、ある時点で不変参照がいくつでも存在するか、または可変参照が一つだけ存在できることができます。これによりデータ競合が防止されます。間違ったコードの例:
let mut s = String::from("hi"); let r1 = &mut s; let r2 = &mut s; // コンパイルエラー!
事例
あるマルチスレッドプロジェクトでは、開発者が所有権を使わずに可変バッファの参照を保持しようとしたため、バッファが解放される前に参照を使おうとしたことでエラーが発生(use-after-free)しました。Rustはそのようなコードのコンパイルを許可しなかったため、アーキテクチャを変更せざるを得ませんでした。
事例
大規模Rustプロジェクトの開始時、プログラマはC++からコードを移行していました。彼らは「生」のポインタを使う古い習慣を統合しようとしたため、リソースの所有権に関するエラーや、所有権のアーキテクチャの問題が解決されるまでborrow checkerのパニックが頻繁に発生しました。
事例
文字列解析ライブラリでは、Rustの厳格な所有権システムのおかげで二重解放エラーを回避することができました。C++で同様のライブラリは、捕まえにくいバグやメモリリークを引き起こしていました。