注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
Rustは標準ライブラリに異なるスマートポインタの型を幾つか用意していますが、更に特殊な型が2つあります。Rustの安全性の多くはコンパイル時のチェックに依るものですが、生ポインタを用いるとそういった保証が得られないため unsafe です。
*const T
と *mut T
はRustにおいて「生ポインタ」と呼ばれます。時々、ある種のライブラリを書く際に、あなたは何らかの理由でRustが行う安全性の保証を避けなければならないこともあります。このようなケースでは、ユーザに安全なインターフェースを提供しつつ、ライブラリの実装に生ポインタを使用できます。例えば、 *
ポインタはエイリアスとして振る舞うこともできるので、所有権を共有する型を書くのに用いたり、スレッドセーフな共有メモリ型でさえも実装できます。( Rc<T>
と Arc<T>
型は完全にRustのみで実装されています)
以下は覚えておくべき生ポインタとその他のポインタ型との違いです。
Box
と &
では保証される)Box
とは異なり、自動的な後処理が一切行われないため、手動のリソース管理が必要&
と異なり、ライフタイムの機能が無効化されるため、コンパイラはダングリングポインタを推論できない*const T
を直接介した変更は拒むが、それ以外のエイリアシングやミュータビリティに関する保証はない生ポインタを作成すること自体は絶対に安全です。
fn main() { 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; let mut y = 10; let raw_mut = &mut y as *mut i32;
しかしながら参照外しは安全ではありません。以下は動作しないでしょう。
fn main() { let x = 5; let raw = &x as *const i32; println!("raw points at {}", *raw); }let x = 5; let raw = &x as *const i32; println!("raw points at {}", *raw);
このコードは以下のエラーが発生します。
error: dereference of raw 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を使う際に役立ちます。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
の有効な実体を指さなければならないのです。その上、ポインタは参照のエイリアシングとミュータビリティの規則も満たす必要があります。コンパイラはあらゆる参照についてこれらの性質が真であると仮定しており、その生成方法に依らず適用するため、生ポインタからのいかなる変換も、参照先の値が上記の性質を満たすと表明していることになります。プログラマがこのことを保証 しなければならない のです。
おすすめの変換の方法は以下のとおりです。
fn main() { // explicit cast // 明示的キャスト let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; // implicit coercion // 暗黙的キャスト 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; } }// 明示的キャスト 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
とは異なります)