項目16:unsafeコードを書かないようにしよう
unsafe コードは極力避けるべきであり、FFI や低レイヤ実装、実現したい機能が標準ライブラリや crates.io に無い場合を除いて使うべきではない Rust のメモリ安全性は、実行時のオーバーヘッド無しで保証される
この保証を得るために、Rust を書く際には 借用チェッカ に対応するコードを記述する必要があり、使用する 参照型 を正確に指定する必要がある Unsafe Rust の概要
具体的には、ブロックの前に unsafe と書くことで、そのブロック内は unsafe モード実行されるようになる
このモードでは、通常の Rust では許可されていない操作が可能になる
生ポインタは 借用ルール の対象外であり、デリファレンス 時や有効なメモリを指していることを、プログラマが保証する必要がある なぜ Unsafe Rust を避けるべきか
Rust に移行しても、結局 Rust 内で C のようなコードを書くなら意味がないため
しかし、unsafe コードが必要になるケースもある
e.g. 低レベル なライブラリのコードを書く場合や、他言語のコードと連携する必要がある場合 「unsafe コードは書かないようにしよう」
この項目のタイトルの中で重要なのは「書く」という点
ほとんど場合、必要な unsafe なコードはすでに誰かが書いているため、自身で書く必要は上記を除いてほとんど無い
標準ライブラリにおける unsafe コード
標準ライブラリではたくさんの unsafe コードが含まれている
e.g.
スマートポインタ型(Rc や RefCell、Arc など)
unsafe なコード(特に生ポインタ)を内部的に用いて、それぞれ固有の セマンティクス をユーザに提供する 同期プリミティブ(Mutex や RwLock、それぞれに対応するガード)
unsafe な OS 固有のコードを内部的に用いている アトミックとは、複数スレッドが同じ変数を操作しても データ競合 が起きないことを意味する 借用チェッカ の制約を回避しながら、メモリ内の値を操作する機能を提供する これらの機能を正しく使うにはまだ注意が必要だが、unsafe コードはカプセル化されて隠蔽されているので、様々な問題が起きないようになっている
e.g.
unsafe が必要になる場合の対応
unsafe を使わざるを得ないケースもある
e.g. 他言語のコードと相互運用するために FFI を用いるケース しかし、このような場合でも unsafe コードをラップする 層 を作り、その中に unsafe 操作を閉じ込める のが良い unsafe コードを書く際の注意点
unsafe ブロックを最小化する
unsafe コードの範囲をできるだけ小さくすることで、失敗した場合の影響範囲を限定する
普段以上にテストを書く
Miri は コンパイラ の出力する IR を解釈するので、コンパイラが検出できない様々なエラーを検知できる マルチスレッドでの使用は慎重に考える