不健全な操作
このセクションの序文として、公式ドキュメントから引用すると、「コードベース内の不健全なコードの量を最小限に抑えるように努めるべきである」とあります。このことを念頭に、始めましょう!Rust の不健全な注釈は、コンパイラによって設けられた保護を回避するために使用されます。具体的には、不健全なものが使用される主な 4 つのことがあります。
- 生のポインターの参照解除
unsafe
な関数またはメソッドの呼び出し(FFI を介した関数の呼び出しも含む。本書の前の章を参照)
- 静的な可変変数のアクセスまたは変更
- 不健全なトレイトの実装
生のポインター
生のポインター *
と参照 &T
は同じように機能しますが、参照は常に安全です。なぜなら、借用チェッカーにより、有効なデータを指すことが保証されているからです。生のポインターの参照解除は、不健全なブロックを通じてのみ行うことができます。
fn main() {
let raw_p: *const u32 = &10;
unsafe {
assert!(*raw_p == 10);
}
}
不健全な関数の呼び出し
一部の関数は unsafe
として宣言できます。これは、コンパイラではなくプログラマが正しさを保証する責任があることを意味します。この例の 1 つが [std::slice::from_raw_parts
] で、これは最初の要素へのポインターと長さを与えることでスライスを作成します。
use std::slice;
fn main() {
let some_vector = vec![1, 2, 3, 4];
let pointer = some_vector.as_ptr();
let length = some_vector.len();
unsafe {
let my_slice: &[u32] = slice::from_raw_parts(pointer, length);
assert_eq!(some_vector.as_slice(), my_slice);
}
}
slice::from_raw_parts
について、必ず守らなければならない仮定の 1 つは、渡されたポインターが有効なメモリを指しており、そのメモリが正しい型であるということです。これらの不変条件が守られない場合、プログラムの動作は未定義となり、何が起こるかはわかりません。