参照型とポインタ型
参照型とポインタ型
- 参照型
&T
/&mut T
- ある所有された値への借用を表す型 - ポインタ型
*const T
/*mut T
-null
を表すことができる
ポインタ型を使うメリットとデメリット
Rustではポインタ型は、値がnullの可能性がある。 したがって扱う場合は、unsafeブロック内部で行う必要がある。 その代わり、Cポインタのように配列の走査が行える。
ポインタ型
変数宣言時に、初期化せずに、nullを代入することが出来る。 ただし、参照外し(*演算子を使って)がされた場合は、非nullで、かつ初期化された値を返す必要がある。
fn main() { let p: *const u8; unsafe { p = "ABC".as_ptr(); println!("{:?}", *p as char); // u8からcharにキャスト println!("{:?}", *p.add(1) as char); println!("{:?}", *p.add(2) as char); } }
*p
: 参照外しに寄ってu8
に変換
ポインタ型の作り方
1. 参照強制(&T or &mut T)による生成
let my_num: i32 = 10; let ptr_my_num: *const i32 = &my_num; // アノテーションを付ける必要がある let mut my_speed: i32 = 88; let ptr_my_speed: *mut i32 = &mut my_speed;
NOTE:
2. Box型から値を取り出して生成
let my_num: Box<i32> = Box::new(10); let p_my_num: *const i32 = &*my_num;
NOTE:
- Box型はスマートポインタなので、
*演算子(参照外し演算子)
によって内部の値を取り出せる - &演算子によってポインタ型に変換している
3. Cから取得する
extern crate libc; use std::mem; unsafe { let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32; if my_num.is_null() { panic!("failed to allocate memory"); } libc::free(my_num as *mut libc::c_void); }
一般的に、 Rustからmalloc,freeを直接使わない。 しかし、C APIはたくさんのポインタを手渡しするため、Rustにおいてもポインタとして扱う。
ポインタ型の使い方
配列走査などをポインタ型で行うと、処理速度の向上が見込めるが、nullもしくは未初期化やオーバーフローしている可能性があるため、unsafeブロック内部で処理を記述する必要がある。
値の取得
fn main() { let s: &str = "ABC"; let ptr: *const u8 = s.as_ptr(); unsafe { println!("{}", *ptr); // 先頭ポインタ(u8)の値を指し示す。型はu8。 println!("{}", *ptr.offset(0) as char); // A println!("{}", *ptr.offset(1) as char); // B } }
*
演算子- ポインタが指し示している先頭の値を指し示す
- unsafeブロック内部で使用する必要がある
offset(self, count: isize)
- ポインタからのオフセットを計算する
- countの単位は、
size_of::<T>()
バイト毎になる - コンビニエンスメソッドとして、
add(count: usize)
,sub(count: usize)
が存在する
let s: &str = "ABC"; unsafe { let end: *const u8 = s.as_ptr().add(3); println!("{}", *end as char); // LF(0xA)を指し示している println!("{}", *end.sub(1) as char); // C println!("{}", *end.sub(2) as char); // B }
- addに指定するcountによっては、オーバーフローしている可能性がある
値の走査
文字の検索
fn main() { let text = "A language empowering everyone to build reliable and efficient software."; let word = "everyone"; let p_text: *const u8 = text.as_ptr(); let p_word: *const u8 = word.as_ptr(); let mut exist = false; 'i: for i in 0..text.len() { 'j: for j in 0..word.len() { unsafe { if *p_text.add(i + j) != *p_word.add(j) { break 'j; } } if j == word.len() - 1 { exist = true; break 'i; } } } println!("result = {}", exist); }
関連
スマートポインタ https://yossan.hatenablog.com/entry/2020/09/20/224329
Dynamically Sized Type (DST) https://yossan.hatenablog.com/entry/2020/10/11/230422
参照
Primitive Type pointer https://doc.rust-lang.org/std/primitive.pointer.html