構造体からRustの特徴であるトレイトベースのジェネリクスまでの流れを翻訳します。
なまぽは無関係そうに見えますが次回使います。
前: 5.20. Traits 次: 5.23. Trait Objects
この辺から訳の精度に自身が無くなりつつ有るので、
誤訳や改善案等、見つけた場合はご指摘の程宜しくお願いします。
- 元記事 : https://doc.rust-lang.org/stable/book/raw-pointers.html のRust1.2時点
- ライセンス : MIT license, Apache License 2.0.
- See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.
生ポインタ
Rustは標準ライブラリにスマートポインタ1の型を幾つか用意していますが、加えて2つ特別な型があります。Rustの安全性の多くはコンパイル時のチェックから来ていますが、生ポインタやunsafeを使用するとそれらのような保証が得られません。
*const Tと*mut TはRustにおいて'生ポインタ'と呼ばれます。時々、特定の種類のライブラリを書く時に、あなたは幾つかの理由でRustが行う安全性の保証を避けなければならないことがあります。今回のケースでは、ユーザに安全なインターフェースを提供するライブラリを実装する際に生ポインタを使用できます。例えば、ポインタはエイリアスとして振る舞うこともできるので、所有権を共有する型や、スレッドセーフな共有メモリ型でさえも実装することができます。(Rc<T>とArc<T>型は完全にRustのみで実装されています)
以下は覚えておくべき生ポインタとその他のポインタ型との違いです。
- 正しいメモリを指しているか保証されず、nullでないかどうかも保証されない(
Boxと&では保証される) - 自動的な後処理は一切行われず、
Boxとは異なり、手動によるリソースの管理が必要 - plain-old-data型2であるため、所有権を移譲できず、従ってRustのコンパイラはuse-after-free3のような脆弱性を防ぐことができない
- 生存期4の形式が欠如しているため、
&と異なり、コンパイラはダングリングポインタを推論できない -
*const Tを直接介した変更は拒むが、それ以外のエイリアシングや可変性に関する保証はない
基本
生ポインタを作成すること自体は絶対に安全です。
let x = 5;
let raw = &x as *const i32;
let mut y = 10;
let raw_mut = &mut y as *mut i32;
しかしながら、ポインタの指す先を参照するのは安全ではありません。
let x = 5;
let raw = &x as *const i32;
println!("raw points at {}", *raw);
このようなエラーが発生します。
error: dereference of unsafe pointer requires unsafe function or block [E0133]
println!("raw points at{}", *raw);
^~~~
あなたが生ポインタを参照するとき、間違っている所を指していないという責任を負わなければなりません。ですので、あなたはunsafeを使う必要があります。
let x = 5;
let raw = &x as *const i32;
let points_at = unsafe { *raw };
println!("raw points at {}", points_at);
生ポインタの操作に関する詳細は、APIドキュメントを参照してください。
FFI
生ポインタはFFI関係で役立ちます。Rustの*const Tと*mut TはそれぞれCのconst T*とT*に似ているからです。これについての詳細は、FFIの章を参照してください。
参照と生ポインタ
実行時において、同じデータを指す生ポインタと参照は同一の内部表現を持ちます。実際、unsafeを使っていない範囲においては&Tは暗黙的に*const Tへキャスト可能であり、mutの場合も同様です。(value as *const T及びvalue as *mut Tへ明示的にキャストすることも可能です)
反対に、*constから&へキャストするのは安全ではありません。&Tは常に有効であるため、最低でも*const Tは型Tの有効な実体を指さなければなりません。その上、ポインタは参照のエイリアシングと可変性の規則も満たす必要があります。コンパイラは全ての参照についてこれらのプロパティが真であることを前提としているため、その生成方法によらず、生ポインタからのあらゆるキャストもまた真であることを断言できなければなりません。プログラマがこのことを保証しなければならないのです。
おすすめの変換の方法は以下のとおりです。
let i: u32 = 1;
// 明示的キャスト
let p_imm: *const u32 = &i as *const u32;
let mut m: u32 = 2;
// 暗黙的変換
let p_mut: *mut u32 = &mut m;
unsafe {
let ref_imm: &u32 = &*p_imm;
let ref_mut: &mut u32 = &mut *p_mut;
}
&*xによって参照するスタイルはtransmuteを用いるよりも好ましいです。後者は必要以上に強力ですし、より用途が限定されている操作の方が間違いにくいでしょう。例えば、前者の方法はxがポインタである必要があります。(transmuteとは異なります)