はじめに
この実験では、Rust の不健全な操作を調べます。これらの操作は、コンパイラの保護を回避するために使用され、通常、生のポインターの参照解除、不健全な関数の呼び出し、静的な可変変数のアクセスまたは変更、および不健全なトレイトの実装に使用されます。これらの操作は、コードベースで最小限に抑える必要があり、安全性を確保するためです。
注: 実験でファイル名が指定されていない場合は、好きなファイル名を使用できます。たとえば、
main.rsを使用して、rustc main.rs &&./mainでコンパイルして実行できます。
不健全な操作
このセクションの序文として、公式ドキュメントから引用すると、「コードベース内の不健全なコードの量を最小限に抑えるように努めるべきである」とあります。このことを念頭に、始めましょう!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 つは、渡されたポインターが有効なメモリを指しており、そのメモリが正しい型であるということです。これらの不変条件が守られない場合、プログラムの動作は未定義となり、何が起こるかはわかりません。
まとめ
おめでとうございます!あなたは不健全な操作の実験を完了しました。あなたの技術を向上させるために、LabEx でさらに多くの実験を行って練習してください。