Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

安全でない操作

この章の内容を見る前に、公式ドキュメントから引用した次の文章をお読みください。「コードベース中の、アンセーフな操作をするコードの量は、可能な限り小さく無くてはならない。」この戒めを頭に叩き込んだ上で、さあはじめましょう!Rustにおいて、アンセーフなブロックはコンパイラのチェックをスルーするために使われます。具体的には以下の4つの主要なユースケースがあります。

  • 生ポインタのデリファレンス
  • 安全でない関数やメソッドの呼び出し(FFI経由の関数の呼び出しを含む (詳細は 本書のFFIに関する説明 を参照ください))
  • 静的なミュータブル変数へのアクセスや変更
  • 安全でないトレイトの実装
  • accessing elements of a union

生ポインタ

生ポインタ*と参照&Tはよく似た機能を持ちますが、後者は必ず有効なデータを指していることが借用チェッカーによって保証されているので、常に安全です。生ポインタのデリファレンスはアンセーフなブロックでしか実行できません。

fn main() {
    let raw_p: *const u32 = &10;

    unsafe {
        assert!(*raw_p == 10);
    }
}

安全でない関数呼び出し

関数は unsafe として宣言できます。これはコンパイラの代わりにプログラマの責任で正しさを保証することを意味します。例として 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 は、次のふたつの仮定に基づいて処理します。ひとつは渡されたポインタが有効なメモリ位置を指していること、もうひとつはそのメモリに格納された値が正しい型であることです。この仮定を満たさない場合、プログラムの動作は不定となり、何が起こるかわかりません。

Union Elements

Elements of unions overlap in memory, thus changing the value of one element automatically changes every element’s value. They can be used, if you don’t know which data type you will need at runtime. Since Rust offers safe Enums, the main purpose of Unions is to allow interacting with C code. Accessing and changing elements of unions is only allowed in unsafe Rust.

union MyFirstUnion {
    float: f32,
    integer: u32
}

fn main() {
    // Creating an object of a union type doesn't require Unsafe Rust.
    let mut u = MyFirstUnion { float: 123.45 };
    
    // Reading and changing u.float or u.integer is only allowed in Unsafe Rust.
    unsafe {
        assert_eq!(u.float, 123.45);
        println!("u.float = 123.45, but u.integer = {}", u.integer);

        u.integer = 42;
        assert_eq!(u.integer, 42);
        println!("u.integer = 42, but u.float = {}", u.float);
    }
}