Rust: unsafe
例.rspub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Ascii {
Ascii(bytes)
}
unsafe
とは?
Rustはメモリ安全性を保証するために厳格なコンパイル時チェックを行います。
しかし、特定の低レベル操作やパフォーマンスの最適化のために、この安全性を一部無効にする必要が生じる場合があります。
そこで登場するのが unsafe
キーワードです。
unsafe
ブロックや unsafe
関数を使用することで、Rustのコンパイラによる一部の安全性チェックを回避し、開発者が責任を持って安全性を確保することが可能になります。
unsafe
が必要な理由
1. 低レベルのメモリ操作: 生ポインタの操作や、直接メモリにアクセスする必要がある場合。
2. 外部ライブラリとの連携: C言語などの外部コードとインターフェースする際。
3. パフォーマンス最適化: 高速化のために安全チェックを省略する場合。
unsafe
で許可される操作
生ポインタのデリファレンス: *const T
や *mut T
といった生ポインタを直接操作。
外部関数の呼び出し: extern
ブロック内の関数を呼び出す。
静的変数の変更: 不変とされている静的変数を変更。
unsafe
関数やメソッドの呼び出し。
安全性の確保
unsafe
を使用する際は、以下の点に注意して安全性を確保する必要があります:
データ競合の回避: 複数のスレッドから同時にアクセスされても問題が起きないようにする。
有効なメモリアドレスの使用: ポインタが有効なメモリを指していることを保証。
正しい外部関数の使用: 外部ライブラリの仕様に従って正しく関数を呼び出す。
サンプルコード
以下に、 unsafe
を使用して生ポインタをデリファレンスする簡単な例を示します。
rustfn main() {
let x = 42;
let ptr = &x as *const i32;
unsafe {
// 生ポインタをデリファレンスして値を取得
println!("値: {}", *ptr);
}
}
1. x
という整数を定義し、その参照を生ポインタ ptr
に変換しています。
2. unsafe
ブロック内で、生ポインタ ptr
をデリファレンスして値を取得し、表示しています。
3. unsafe
ブロックを使用することで、コンパイラに対して「ここで安全性を自分で保証します」と伝えています。
型安全性の保守的な部分を一部緩めるイメージ
バグはないんだから、型検査緩めてくれよ!ってやる
だからunsafeがあるのが一概に悪いというわけではない
ただ、コンパイラのサポートを一部得られないことを意味する
>"Rust 研究者" として個人的に「Rust で困ったらガンガン unsafe を使えばいい」主義を応援しています
>Rust の軽量な静的検査のもとで無条件に安全なものだけが safe で、unsafe はそれ以外の全てなので、「unsafe は即危険」ではなくて、多くの場合に何らかの条件のもとで安全性が担保されます
>Rust の単純な静的検査でカバーしきれないのはむしろ自然なことなので、臆せず unsafe を使えばいいと思います
>関数はデフォルトで unsafe にしておいて、「この所有権型で無条件で安全になる」と確信できる関数だけ safe にしていく方針を取ると、気が楽になると思います
>仮に unsafe を使いまくっていたとしても、多くの場所で安全性が担保されるおかげで本当に危険な場所だけ注意すれば良くなるし、Rust を使う価値が十分にあると思います
>爽快に unsafe を使いこなして、Rust をガンガン書いていきましょう