Rust 語言學習之旅(7)
Vec<T> 和 String
Vec<T> 是一個智慧指標,它只擁有一些位元組的記憶體區域。 Rust 編譯器不知道這些位元組中存在著什麼。 智慧指標解釋從它管理的記憶體區域獲取資料意味著什麼,跟蹤這些位元組中的資料結構開始和結束的位置,最後將指標解引用到資料結構中, 成為一個漂亮乾淨的可以閱讀的介面供我們使用(例如my_vec[3])。
類似地,String 跟蹤位元組的記憶體區域,並以程式設計方式將寫入其中的內容限制為始終有效的 utf-8,並幫助將該記憶體區域解引用為型別 &str。
這兩種資料結構都使用不安全的解引用指標來完成它們的工作。
記憶體細節:
use std::alloc::{alloc, Layout}; use std::ops::Deref; struct Pie { secret_recipe: usize, } impl Pie { fn new() -> Self { // let's ask for 4 bytes let layout = Layout::from_size_align(4, 1).unwrap(); unsafe { // 分配記憶體位置並將其儲存為數字 let ptr = alloc(layout) as *mut u8; // 使用指標數學並寫一些 // u8 值到記憶體 ptr.write(86); ptr.add(1).write(14); ptr.add(2).write(73); ptr.add(3).write(64); Pie { secret_recipe: ptr as usize } } } } impl Deref for Pie { type Target = f32; fn deref(&self) -> &f32 { // 將 secret_recipe 指標解釋為 f32 原始指標 let pointer = self.secret_recipe as *const f32; // 將其解引用為返回值 &f32 unsafe { &*pointer } } } fn main() { let p = Pie::new(); // 透過取消引用我們的“make a pie” // Pie 結構智慧指標 println!("{:?}", *p); } |
Box 是一個可以讓我們將資料從棧移動到堆的智慧指標。
解引用可以讓我們以人類更容易理解的方式使用堆分配的資料,就好像它是原始型別一樣。
struct Pie; impl Pie { fn eat(&self) { println!("tastes better on the heap!") } } fn main() { let heap_pie = Box::new(Pie); heap_pie.eat(); } |
引用計數Rc
Rc 是一個能將資料從棧移動到智慧指標。 它允許我們克隆其他Rc智慧指標,這些指標都具有不可改變地借用放在堆上的資料的能力。
只有當最後一個智慧指標被刪除時,堆上的資料才會被釋放。
use std::rc::Rc; struct Pie; impl Pie { fn eat(&self) { println!("tastes better on the heap!") } } fn main() { let heap_pie = Rc::new(Pie); let heap_pie2 = heap_pie.clone(); let heap_pie3 = heap_pie2.clone(); heap_pie3.eat(); heap_pie2.eat(); heap_pie.eat(); // all reference count smart pointers are dropped now // the heap data Pie finally deallocates } |
共享訪問RefCel
RefCell 是一個容器資料結構,通常由智慧指標擁有,它接收資料並讓我們借用可變或不可變引用來訪問內部內容。 當您要求借用資料時,它透過在執行時強制執行 Rust 的記憶體安全規則來防止借用被濫用
只有一個可變引用或多個不可變引用,但不能同時有!
如果你違反了這些規則,RefCell 將會panic。
use std::cell::RefCell; struct Pie { slices: u8 } impl Pie { fn eat(&mut self) { println!("tastes better on the heap!"); self.slices -= 1; } } fn main() { // RefCell 在執行時驗證記憶體安全性 // 注意:pie_cell 不是 mut! let pie_cell = RefCell::new(Pie{slices:8}); { // 但我們可以借用可變引用! let mut mut_ref_pie = pie_cell.borrow_mut(); |
執行緒間共享
Mutex 是一種容器資料結構,通常由智慧指標持有,它接收資料並讓我們借用對其中資料的可變和不可變引用。 這可以防止借用被濫用,因為作業系統一次只限制一個 CPU 執行緒訪問資料,阻塞其他執行緒,直到原執行緒完成其鎖定的借用。
多執行緒超出了 Rust 之旅的範圍,但 Mutex 是協調多個 CPU 執行緒訪問相同資料的基本部分。
有一個特殊的智慧指標 Arc,它與 Rc 相同,除了使用執行緒安全的引用計數遞增。 它通常用於對同一個 Mutex 進行多次引用。
組合智慧指標
智慧指標看起來可能會存在一些限制,但是我們可以做一些非常有用的結合。
Rc<Vec<Foo>> - 允許克隆多個可以借用堆上不可變資料結構的相同向量的智慧指標。
Rc<RefCell<Foo>> - 允許多個智慧指標可變/不可變地借用相同的結構Foo
Arc<Mutex<Foo>> - 允許多個智慧指標以 CPU 執行緒獨佔方式鎖定臨時可變/不可變借用的能力。
記憶體細節:
- 您會注意到一個包含許多這些組合的主題。 使用不可變資料型別(可能由多個智慧指標擁有)來修改內部資料。 這在 Rust 中被稱為“內部可變性”模式。 這種模式讓我們可以在執行時以與 Rust 的編譯時檢查相同的安全級別來改變記憶體使用規則。
use std::cell::RefCell; use std::rc::Rc; struct Pie { slices: u8, } impl Pie { fn eat_slice(&mut self, name: &str) { println!("{} took a slice!", name); self.slices -= 1; } } struct SeaCreature { name: String, pie: Rc<RefCell<Pie>>, } impl SeaCreature { fn eat(&self) { // 使用指向 pie 的智慧指標進行可變借用 let mut p = self.pie.borrow_mut(); // take a bite! p.eat_slice(&self.name); } } fn main() { let pie = Rc::new(RefCell::new(Pie { slices: 8 })); // ferris 和 sarah 獲得了指向 pie 的智慧指標的克隆 let ferris = SeaCreature { name: String::from("ferris"), pie: pie.clone(), }; let sarah = SeaCreature { name: String::from("sarah"), pie: pie.clone(), }; ferris.eat(); sarah.eat(); let p = pie.borrow(); println!("{} slices left", p.slices); } |
智慧指標是 Rust程式設計中經常使用的,它可以讓我們不必重新建立非常常見的記憶體使用正規化。 有了它,您可以準備好應對最艱難的挑戰了!
相關文章
- Rust 語言學習之旅Rust
- Rust 語言學習之旅(2)Rust
- Rust 語言學習之旅(6)Rust
- Rust 語言學習之旅(3)Rust
- 從Julia到Rust語言的學習 - miguelrazRust
- Go語言學習(7) - 運算子Go
- Jon Gjengset認為學習Rust語言並不難GseRust
- 這些情況會阻礙你學習Rust語言 - dystroyRust
- C語言學習方法,怎麼學習C語言?C語言
- Rust學習之旅2——常見程式設計概念Rust程式設計
- rust學習四、控制語句Rust
- 學習Rust 基礎語法Rust
- 學習Rust 條件語句Rust
- go語言學習Go
- java語言學習Java
- Rust學習之旅1——寫個猜數字遊戲Rust遊戲
- Go語言學習查缺補漏ing Day7Go
- Go語言學習筆記 - PART7 - 結構體Go筆記結構體
- Rust語言4歲了 | rust-langRust
- Rust之旅 02.通過例子學習自定義型別Rust型別
- Go語言學習——mapGo
- C語言再學習C語言
- C語言學習心得C語言
- go語言學習-介面Go
- go語言學習-goroutineGo
- 《快學 Go 語言》第 7 課 —— 字串Go字串
- Solidity語言學習筆記————7、單位和全域性變數Solid筆記變數
- 8.17----學習JAVA語言Java
- 7.27----學習JAVA語言Java
- c語言基礎學習C語言
- GO語言學習——切片二Go
- C語言指標學習C語言指標
- go 語言指標學習Go指標
- C 語言學習筆記筆記
- Go 語言學習腦圖Go
- C語言深入學習二C語言
- C語言學習 相同元素C語言
- C語言學習筆記C語言筆記