最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析Rust中的智能指針

 更新時間:2025年10月27日 09:32:47   作者:alwaysrun  
本文介紹了Rust中的智能指針,Box、Rc、Arc、RefCell、Mutex、RwLock對應(yīng)的功能、場景與常用方法,并提供了組合使用方式,以及Cow、Pin的使用方式,感興趣的朋友跟隨小編一起看看吧

Rust 中,智能指針是管理堆內(nèi)存的核心工具,它們通過封裝指針并添加額外功能(如所有權(quán)管理、引用計數(shù)等)來提供更安全的內(nèi)存管理。

智能指針

智能指針本質(zhì)是 “擁有數(shù)據(jù)所有權(quán)的結(jié)構(gòu)體”,通過實現(xiàn)以下兩個關(guān)鍵 trait 模擬指針行為:

  • Deref trait:允許智能指針像普通引用一樣被解引用(如*ptr),簡化使用。
  • Drop trait:定義智能指針離開作用域時的 “清理邏輯”(如釋放堆內(nèi)存、減少引用計數(shù)),實現(xiàn)自動內(nèi)存管理。

常見的智能指針

智能指針特點所有權(quán)規(guī)則
Box<T>將數(shù)據(jù)分配在堆上獨(dú)占所有權(quán)(不可復(fù)制)
Rc<T>引用計數(shù)共享多個所有者共享數(shù)據(jù),只讀,單線程共享
Arc<T>原子引用計數(shù)多線程共享、線程安全
RefCell<T>內(nèi)部可變性運(yùn)行時借用檢查,單線程中可變共享
Mutex<T>互斥鎖封裝多線程中安全的可變共享
RwLock<T>讀寫鎖封裝多讀單寫共享

Box

Box<T>(“盒子”)是最基礎(chǔ)的智能指針,用于將數(shù)據(jù)存儲在堆上,而Box自身(指針)存儲在棧上:

  • 獨(dú)占所有權(quán):一個Box擁有堆數(shù)據(jù)的唯一所有權(quán),轉(zhuǎn)移Box會轉(zhuǎn)移所有權(quán)。
  • 自動釋放:當(dāng)Box離開作用域時,會調(diào)用Drop釋放堆上的數(shù)據(jù)。

使用場景:

  • 編譯時大小不確定的類型(如遞歸類型)
  • 轉(zhuǎn)移大量數(shù)據(jù)時避免棧復(fù)制(直接轉(zhuǎn)移Box指針,而非堆數(shù)據(jù))
  • 實現(xiàn) trait 對象(dyn Trait),如集合中存儲多種類型數(shù)據(jù)時
#[derive(Debug)]
enum MyList {
    Cons(i32, Box<MyList>), // 必須為Box,此處為遞歸,大小不確定
    Nil,
}
use MyList::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));
println!("Recursive list: {:?}", list);

常用方法

方法說明
Box::new(value)創(chuàng)建一個堆上分配的對象
*box解引用,訪問內(nèi)部值
Box::leak(box)將 Box 轉(zhuǎn)為 'static 引用(泄露內(nèi)存)
Box::into_raw(box)轉(zhuǎn)為裸指針(不再自動釋放)
Box::from_raw(ptr)從裸指針恢復(fù)(恢復(fù)自動釋放)

作為trait對象:

// 定義trait
trait Shape {
    fn area(&self) -> f64;
}
// 實現(xiàn)trait的結(jié)構(gòu)體
struct Circle { radius: f64 }
impl Shape for Circle {
    fn area(&self) -> f64 { std::f64::consts::PI * self.radius.powf(2.0) }
}
struct Square { side: f64 }
impl Shape for Square {
    fn area(&self) -> f64 { self.side.powf(2.0) }
}
fn main() {
    // 用Box<dyn Shape>存儲不同類型的Shape實現(xiàn)
    let shapes: Vec<Box<dyn Shape>> = vec![
        Box::new(Circle { radius: 1.0 }),
        Box::new(Square { side: 2.0 }),
    ];
    // 動態(tài)調(diào)用area方法(運(yùn)行時確定具體類型)
    for shape in shapes {
        println!("面積:{:.2}", shape.area()); 
        // 輸出:3.14(圓)、4.00(正方形)
    }
}

Rc

Rc<T>(Reference Counted,引用計數(shù))用于單線程中多個所有者共享同一份堆數(shù)據(jù)。它會在堆上維護(hù)一個 “引用計數(shù)”,當(dāng)計數(shù)歸零時自動釋放數(shù)據(jù)。

  • 共享所有權(quán):通過Rc::clone(&rc)創(chuàng)建新引用,引用計數(shù) +1;每個引用離開作用域時計數(shù) -1。
  • 單線程限制:Rc<T>的引用計數(shù)操作不是原子的,線程不安全,不能用于多線程。
  • 只讀訪問:Rc<T>只能提供不可變引用(避免數(shù)據(jù)競爭)。

常用方法

方法說明
Rc::new(value)創(chuàng)建一個引用計數(shù)智能指針
Rc::clone(&rc)增加引用計數(shù)(輕量)
Rc::strong_count(&rc)獲取當(dāng)前強(qiáng)引用計數(shù)
Rc::weak_count(&rc)獲取當(dāng)前弱引用計數(shù)
Rc::downgrade(&rc)獲取弱引用(不增加強(qiáng)計數(shù))

查看引用計數(shù):

use std::rc::Rc;
fn main() {
    let a = Rc::new(String::from("hello"));
    let b = Rc::clone(&a);
    let c = Rc::clone(&a);
    println!("count = {}", Rc::strong_count(&a)); // 輸出 3
    println!("{}", b);
} // 所有 Rc 離開作用域后才釋放堆內(nèi)存

Arc

Arc<T>(Atomic Rc)是Rc<T>的線程安全版本,其引用計數(shù)操作通過原子指令實現(xiàn),可用于多線程環(huán)境。

  • 跨線程共享:允許在多個線程中共享數(shù)據(jù)(需配合Send/Sync trait)。
  • 原子操作:計數(shù)增減是原子的,避免多線程競爭問題(但性能略低于Rc<T>)。

常用方法

方法說明
Arc::new(value)創(chuàng)建智能指針
Arc::clone(&arc)增加引用計數(shù)(原子操作)
Arc::strong_count(&arc)當(dāng)前強(qiáng)引用計數(shù)
Arc::downgrade(&arc)獲取弱引用

多線程引用計數(shù):

use std::sync::Arc;
use std::thread;
pub fn arc_test() {
    let data = Arc::new(100); // 堆上的數(shù)據(jù),原子引用計數(shù)=1
    let mut handles = vec![];
    // 創(chuàng)建3個線程共享data
    for i in 0..3 {
        let d = Arc::clone(&data); // 計數(shù)+1(原子操作)
        handles.push(thread::spawn(move || {
            println!("i: {}", d);
        }));
    }
    println!("before ref-count: {:?}", Arc::strong_count(&data));
    for h in handles {
        h.join().unwrap();
    }
    println!("after ref-count: {:?}", Arc::strong_count(&data)); // 原子引用計數(shù)=1
}

RefCell

RefCell<T>用于編譯期不滿足借用規(guī)則,但運(yùn)行時可安全修改數(shù)據(jù)的場景。它實現(xiàn)了 “內(nèi)部可變性”(Interior Mutability):允許通過不可變引用修改數(shù)據(jù),借用規(guī)則的檢查推遲到運(yùn)行時(違反時觸發(fā)panic)。

  • 運(yùn)行時檢查:通過borrow()(不可變借用)和borrow_mut()(可變借用)獲取內(nèi)部數(shù)據(jù)的引用,運(yùn)行時確保 “同一時間最多一個可變引用,或多個不可變引用”。
  • 單線程限制:RefCell<T>非線程安全,不能跨線程使用。

常用方法

方法說明
RefCell::new(value)創(chuàng)建一個內(nèi)部可變?nèi)萜?/td>
borrow()不可變借用(運(yùn)行時檢查)
borrow_mut()可變借用(運(yùn)行時檢查)
.try_borrow()
/ .try_borrow_mut()
嘗試借用,返回 Result
避免 panic

在Rc中嵌套使用

use std::rc::Rc;
use std::cell::RefCell;
pub fn refcell_test() {
    let shared_data = Rc::new(RefCell::new(0)); // 堆上的0,可共享且修改
    let a = Rc::clone(&shared_data);
    let b = Rc::clone(&shared_data);
    *a.borrow_mut() += 10; // a修改數(shù)據(jù)
    *b.borrow_mut() += 5; // b修改數(shù)據(jù)
    println!("{}", shared_data.borrow()); // 輸出15
}

Mutex

多線程并發(fā)編程的核心同步原語之一,用于在多個線程之間安全地共享和修改數(shù)據(jù);Mutex<T> 本身不提供共享所有權(quán),一般需要將其包裹在 Arc<T>中,在在多個線程間共享:

  • 多線程可變共享;
  • 確保同一時間只有一個線程訪問。

常用方法

方法說明
Mutex::new(value)創(chuàng)建互斥鎖
lock()獲取鎖(阻塞)
try_lock()嘗試獲取鎖(立即返回 Result
into_inner()取出內(nèi)部值(消耗鎖)

與Arc一起在多線程中使用:

use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..5 {
        let c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            let mut num = c.lock().unwrap();
            *num += 1;
        }));
    }
    for h in handles {
        h.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

RwLock

允許多個線程同時讀取共享數(shù)據(jù),但寫入時必須獨(dú)占訪問,從而在保證線程安全的同時提升并發(fā)性能。

  • 高并發(fā)讀場景;
  • 多線程下支持多個讀取者或一個寫入者。
    • 多個讀鎖可同時存在;
    • 寫鎖獨(dú)占;
    • 若寫鎖被持有,讀鎖將阻塞。

常用方法

方法說明
RwLock::new(value)創(chuàng)建讀寫鎖
read()獲取只讀鎖(可同時多個)
write()獲取寫鎖(獨(dú)占)
try_read()
/ try_write()
嘗試非阻塞獲取

多讀少寫場景:

use std::sync::RwLock;
use std::thread;
let data = RwLock::new(0);
// 啟動一個寫線程
let w_handle = thread::spawn(move || {
    let mut w = data.write().unwrap();
    thread::sleep(std::time::Duration::from_millis(100));
    *w = 42;
});
// 啟動多個讀線程
let mut r_handles = vec![];
for _ in 0..3 {
    let r_data = data.clone();
    let handle = thread::spawn(move || {
        let r = r_data.read().unwrap(); // 會被寫線程阻塞,直到寫完成
        println!("Read: {}", *r);
    });
    r_handles.push(handle);
}
w_handle.join().unwrap();
for h in r_handles { h.join().unwrap(); }

Weak

Weak<T>Rc<T>/Arc<T>的弱引用,不增加強(qiáng)引用計數(shù),用于打破循環(huán)引用,避免內(nèi)存泄漏。

常用方法

方法說明
Weak::new()創(chuàng)建空的弱引用
Rc::downgrade(&rc)Rc<T>創(chuàng)建Weak<T>(弱引用)
weak.upgrade()Weak<T>轉(zhuǎn)為Option<Rc<T>>(強(qiáng)引用),若數(shù)據(jù)已釋放則返回None
Weak::strong_count(&weak)獲取關(guān)聯(lián)Rc<T>的強(qiáng)引用計數(shù)
Weak::weak_count(&weak)獲取弱引用計數(shù)

Cow寫時Copy

Clone-on-Write(寫時克?。┦且粋€枚舉類型,用于在“可能需要修改借用數(shù)據(jù)”時,避免不必要的復(fù)制。

  • 如果只讀,就直接借用(零拷貝)。
  • 如果要改,就克隆一份(擁有所有權(quán)后修改)。

定義:Cow要么借用&T,要么擁有T(T 必須實現(xiàn) ToOwned)。

enum Cow<'a, B: ?Sized + 'a> where B: ToOwned {
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

常用方法

方法說明
Cow::Borrowed(&T)從借用創(chuàng)建
Cow::Owned(T)從擁有值創(chuàng)建
.to_mut()若為借用則克隆,返回可變引用
.into_owned()獲取擁有所有權(quán)的值(可能克?。?/td>
.is_borrowed()
/ .is_owned()
判斷當(dāng)前狀態(tài)
.as_ref()獲取不可變引用

寫時復(fù)制示例:

use std::borrow::Cow;
fn main() {
    let s = "immutable data".to_string();
    let mut cow = Cow::Borrowed(s.as_str()); // 借用 &str
    println!("Before: {:?}", cow); // Borrowed("immutable data")
    // 調(diào)用 to_mut() 會檢測當(dāng)前是否為借用
    let data = cow.to_mut(); // 克隆一份(從 Borrowed -> Owned)
    data.push_str(" modified");
    println!("After: {:?}", cow);  // Owned("immutable data modified")
}

Pin

Rust 的所有權(quán)系統(tǒng)保證了內(nèi)存安全,但默認(rèn)允許將值從一個內(nèi)存位置移動到另一個位置(例如賦值或函數(shù)返回時)。 Pin用于防止內(nèi)存中對象被移動(pinned in place); 即可以“釘住”一個值,使它在被銷毀前一直位于同一內(nèi)存地址 。

方法 / 操作說明
Pin::new(pointer)安全創(chuàng)建Pin<P>,要求P指向的類型T實現(xiàn)Unpin(可安全移動)。
Pin::new_unchecked(pointer)不安全創(chuàng)建Pin<P>,不要求T: Unpin,但需開發(fā)者保證數(shù)據(jù)不會被移動(否則會導(dǎo)致未定義行為)。
pin.as_ref()獲取Pin<&T>(不可變引用的 Pin)。
pin.as_mut()獲取Pin<&mut T>(可變引用的 Pin)。
Pin::into_inner(pin)消費(fèi)Pin<P>,返回內(nèi)部的指針P(僅當(dāng)T: Unpin時安全,否則可能導(dǎo)致移動)。
pin.get_mut()獲取內(nèi)部指針的&mut P(僅當(dāng)T: Unpin時允許,否則編譯錯誤)。
pin.get_ref()獲取 &T
unsafe fn get_unchecked_mut()獲取 &mut T,不檢查移動安全

Pin與Unpin

Pin<T>的出現(xiàn)就是為了強(qiáng)制數(shù)據(jù)在內(nèi)存中 “固定”,確保其地址不會改變

  • Pin<P>:一個包裝器類型,其中P是一個指針類型(如Box<T>、&mut TArc<T>等)。Pin<P>保證:被P指向的數(shù)據(jù)不會被移動(除非數(shù)據(jù)實現(xiàn)了Unpin)。
  • Unpin trait:標(biāo)記 trait,表明 “該類型的數(shù)據(jù)可以安全移動,即使被Pin包裝”。大多數(shù)類型(如i32、String、Vec<T>等)默認(rèn)自動實現(xiàn)Unpin,無需手動處理;而需要固定的類型(如自引用類型)則不實現(xiàn)Unpin,必須通過Pin確保不被移動。
    • 對于 T: !Unpin(不實現(xiàn)Unpin):Pin<P>會嚴(yán)格限制操作,不允許通過Pin獲取能導(dǎo)致數(shù)據(jù)移動的接口(如&mut T),確保數(shù)據(jù)地址不變。

Rust 中大多數(shù)類型默認(rèn)都實現(xiàn)了 Unpin,這意味著它們可以被安全地移動(move)。而PhantomPinned 是標(biāo)準(zhǔn)庫 std::marker 模塊提供的一個標(biāo)記類型(marker type;本身是一個零大小的結(jié)構(gòu)體(ZST),沒有字段,也不占用內(nèi)存),其主要作用是阻止包含它的類型自動實現(xiàn) Unpin trait。

自引用類型與Pin

自引用類型(如包含自身引用的結(jié)構(gòu)體)是Pin的典型應(yīng)用場景。沒有Pin時,移動會導(dǎo)致懸垂引用;用Pin固定后,地址不變,引用安全。

use std::pin::Pin;
struct SelfRef {
    data: String,
    ptr: *const String,
}
impl SelfRef {
    fn new(txt: &str) -> Pin<Box<SelfRef>> {
        let mut boxed = Box::pin(SelfRef {
            data: String::from(txt),
            ptr: std::ptr::null(),
        });
        let ptr = &boxed.data as *const String;
        unsafe {
            let mut_ref = Pin::as_mut(&mut boxed);
            Pin::get_unchecked_mut(mut_ref).ptr = ptr;
        }
        boxed
    }
    fn show(&self) {
        unsafe {
            println!("data = {}, ptr = {}", self.data, &*self.ptr);
        }
    }
}
fn main() {
    let pinned = SelfRef::new("hello");
    pinned.show();
}

到此這篇關(guān)于Rust中的智能指針的文章就介紹到這了,更多相關(guān)Rust智能指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Rust語言之使用Polar權(quán)限管理方法詳解

    Rust語言之使用Polar權(quán)限管理方法詳解

    權(quán)限管理 (Permission Management) 是一個涵蓋了系統(tǒng)或網(wǎng)絡(luò)中用戶權(quán)限控制和管理的系統(tǒng),本文將詳細(xì)給大家介紹Rust語言中如何使用Polar權(quán)限管理,需要的朋友可以參考下
    2023-11-11
  • 最新Rust錯誤處理簡介

    最新Rust錯誤處理簡介

    Rust并不像C++一樣使用try?catch的異常機(jī)制來進(jìn)行錯誤處理,他將錯誤分為可恢復(fù)錯誤和不可恢復(fù)錯誤兩類,主要使用panic!宏和Result<T,E>類型來進(jìn)行錯誤處理,這篇文章主要介紹了Rust錯誤處理簡介,需要的朋友可以參考下
    2022-11-11
  • Rust  利用 chrono 庫實現(xiàn)日期和字符串互相轉(zhuǎn)換的示例

    Rust  利用 chrono 庫實現(xiàn)日期和字符串互相轉(zhuǎn)換的示例

    在Rust中,chrono庫提供了強(qiáng)大的日期和時間處理功能,使得日期與字符串之間的轉(zhuǎn)換變得簡單,本文介紹了如何在Rust中使用chrono庫將日期轉(zhuǎn)換成字符串,以及如何將字符串解析為日期,對于需要進(jìn)行日期時間格式化、解析或進(jìn)行時區(qū)處理的開發(fā)者來說,chrono庫是一個不可或缺的工具
    2024-11-11
  • Rust中的Vector多值存儲使用方法

    Rust中的Vector多值存儲使用方法

    Vector在Rust中是一個非常靈活和強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),通過有效利用它,我們可以更加方便地處理和操作多個值,使得代碼更加清晰和易于維護(hù),這篇文章主要介紹了Rust中的Vector多值存儲的利器,需要的朋友可以參考下
    2024-02-02
  • Rust 通過異步實現(xiàn)并發(fā)的方法示例

    Rust 通過異步實現(xiàn)并發(fā)的方法示例

    本文主要介紹了Rust 通過異步實現(xiàn)并發(fā)的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • 一文弄懂rust聲明宏

    一文弄懂rust聲明宏

    Rust支持兩種宏,一種是聲明宏,一種是過程宏,本文主要介紹了一文弄懂rust聲明宏,通過聲明宏可以減少一些樣板代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • 使用vscode配置Rust運(yùn)行環(huán)境全過程

    使用vscode配置Rust運(yùn)行環(huán)境全過程

    VS Code對Rust有著較完備的支持,這篇文章主要給大家介紹了關(guān)于使用vscode配置Rust運(yùn)行環(huán)境的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Rust實現(xiàn)構(gòu)建器模式和如何使用Bon庫中的構(gòu)建器

    Rust實現(xiàn)構(gòu)建器模式和如何使用Bon庫中的構(gòu)建器

    這篇文章主要介紹了Rust實現(xiàn)構(gòu)建器模式和如何使用Bon庫中的構(gòu)建器,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Rust之Substrate框架中Core詳解

    Rust之Substrate框架中Core詳解

    Substrate是一個用于構(gòu)建區(qū)塊鏈的開發(fā)框架,它由Parity團(tuán)隊基于Rust語言開發(fā)而成,是一個開箱即用的區(qū)塊鏈構(gòu)造器,本文詳細(xì)介紹了Substrate框架中的Core,需要的朋友可以參考下
    2023-05-05
  • R語言ggplot2繪圖安裝與調(diào)試

    R語言ggplot2繪圖安裝與調(diào)試

    ggplot2是R語言中最常用的繪圖包之一,它提供了一種基于圖層的繪圖語法,使得用戶可以輕松地創(chuàng)建高質(zhì)量的數(shù)據(jù)可視化圖表。在使用ggplot2之前,需要先安裝該包并進(jìn)行調(diào)試。安裝ggplot2可以通過CRAN或GitHub進(jìn)行,調(diào)試則需要注意數(shù)據(jù)格式、語法錯誤等問題。
    2023-06-06

最新評論

仙桃市| 阳春市| 禹州市| 神池县| 鄂托克前旗| 嘉兴市| 叙永县| 沙坪坝区| 弋阳县| 石渠县| 龙陵县| 金川县| 巴中市| 丹江口市| 武城县| 汪清县| 海门市| 壶关县| 金阳县| 天台县| 鄂伦春自治旗| 庆云县| 泽州县| 麻城市| 瓦房店市| 临汾市| 上林县| 鄂尔多斯市| 武清区| 桃江县| 长治市| 桂林市| 秀山| 蒲江县| 吴桥县| 永川市| 津南区| 新安县| 潞西市| 三河市| 象山县|