Rust 中的指針大體可以分為以下四種:
1. 引用就是直接對一個變量執(zhí)行 &、&mut 操作,永遠不會為 null。 與引用相關的一個名詞是 借用(borrowing)。 fn test_ref(){ let mut num = 5; let num_ref = &mut num; *num_ref = 100; println!("{} sizeof &i32 {}", num, std::mem::size_of::<&i32>()) // output 100 sizeof &i32:8} 2. 胖指針比引用多了些其它數(shù)據(jù)。 fn test_fat_pointers(){ let mut arr = [1, 2, 3, 4]; let slice = &mut arr[1..4]; slice[0] = 100; println!("{:?}", arr); // [1, 100, 3, 4] let slice = &arr[1..4]; println!("{:p} {:?}", slice, unsafe { transmute::<_, (usize, usize)>(slice) }); // Output: 0x8a6c0ff4ac (594518471852, 3) // 0x8a6c0ff4ac 594518471852 這兩個值是相等的。 // (594518471852, 3) 分別表示 具體數(shù)據(jù)的堆地址 和 長度 兩個字段。 // 注意這里是用 slice,而不是 &slice。(&slice表示這個變量本身的棧地址) println!("sizeof &[i32]:{}", std::mem::size_of::<&[i32]>()); // Output: sizeof &[i32]:16 // 因為包含了兩個字段:地址 + 長度,所以其占用內存為 2 個 usize 類型大小} 3. 智能指針有特殊功能的,實現(xiàn)了 Deref、drop 相關的trait。 在 rust 中,屬于智能指針的數(shù)據(jù):String、 Vec<T>、Box、Cell、Rc 等等。 每一個智能指針的實現(xiàn)都不大一樣,這里就不再展開敘述。 fn test_smart_pointers(){ // 將本應存在棧上的地址,存在了堆上 let mut num = Box::new(1); // num_address 指向 box 里面的具體內容(也就是儲存在堆上的數(shù)值 1) let num_address : *mut i32 = &mut *num; unsafe { *num_address = 100 } println!("{}", *num + 100) // Output: 200} 4. 裸指針類似 C 語言里面的指針,可以為 null ! 創(chuàng)建裸指針,是 safe 的,讀寫裸指針,才需要 unsafe ! 裸指針又可以分為可變、不可變,分別寫作 *mut T 和 *const T 這里的星號不是解引用運算符,它是類型名稱的一部分。 這里的 T 表示指針指向的具體類型,裸指針本身的的類型大小與 usize 一致。 評論區(qū)有朋友指出:裸指針也能指向不定長類型,而且跟指向不定長類型的引用具有一樣的內存布局。所以調用 sizeof,獲得的大小是原始類型的大小。 fn test_raw_pointers(){ let mut num = 1; // 將引用轉為裸指針 let num_raw_point = &mut num as *mut i32; unsafe { *num_raw_point = 100; println!("{} {} {:p}", num, *num_raw_point, &num); // Output: 100 100 0x8d8c6ff6bc } let address = num_raw_point as usize; // 將一個 usize 對象,轉化為 裸指針 let raw = address as *mut i32; unsafe { *raw = 200; println!("{} {} {:p} {}", num, *num_raw_point, &num, address); // Output: 200 200 0x8d8c6ff6bc 607946536636 }} |
|