0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CRust學(xué)習(xí)筆記:智能指針和內(nèi)部可變性

jf_wN0SrCdH ? 來(lái)源:coding到燈火闌珊 ? 2023-01-29 14:58 ? 次閱讀

本系列文章是Jon Gjengset發(fā)布的CRust of Rust系列視頻的學(xué)習(xí)筆記,CRust of Rust是一系列持續(xù)更新的Rust中級(jí)教程。

我們將通過(guò)手動(dòng)實(shí)現(xiàn)Cell,RefCell來(lái)學(xué)習(xí)智能指針及內(nèi)部可變性。

新建一個(gè)項(xiàng)目:

cargo new --lib pointers
手動(dòng)實(shí)現(xiàn)Cell 在src目錄下新建一個(gè)cell.rs文件,然后在lib.rs中加入:
1modcell;
在cell.rs中寫入如下代碼:
 1usestd::UnsafeCell;
 2
 3pubstructCell{
 4value:UnsafeCell,
 5}
 6
 7implCell{
 8pubfnnew(value:T)->Self{
 9Cell{
10value:UnsafeCell::new(value),
11}
12}
13
14pubfnset(&self,value:T){
15unsafe{
16*self.value.get()=value
17};
18}
19
20pubfnget(&self)->TwhereT:Copy{
21unsafe{
22*self.value.get()
23}
24}
25}

實(shí)現(xiàn)內(nèi)部可變性需要一個(gè)特殊的cell類型,叫作UnsafeCell,它是Rust的核心原語(yǔ)。顧名思義它是不安全的,它持有類型,通過(guò)它可以獲得類型的原生獨(dú)占指針。我們使用UnsafeCell類型可以通過(guò)共享引用轉(zhuǎn)變成獨(dú)占引用來(lái)改變數(shù)據(jù)。

在set和get方法中需要獲取類型的原生的指針,因此需要使用unsafe塊。由于UnsafeCell實(shí)現(xiàn)了!Sync trait,表示不能安全的跨線程共享引用。

測(cè)試代碼如下:

 1#[cfg(test)]
 2modtest{
 3usesuper::Cell;
 4
 5#[test]
 6fncell_test(){
 7letmutx=Cell::new(42);
 8leti=x.get();
 9x.set(43);
10
11assert_eq!(i,42);
12}
13}
執(zhí)行cargo test,測(cè)試通過(guò)。 手動(dòng)實(shí)現(xiàn)RefCell

RefCell的文檔描述是:可以改變內(nèi)存位置,可以動(dòng)態(tài)檢查借用規(guī)則。也就是說(shuō)可以在運(yùn)行期檢查借用規(guī)則。

在src目錄下新建一個(gè)refcell.rs文件,然后在lib.rs中加入:

1modrefcell;
在refcell.rs中寫入如下代碼:
 1usestd::UnsafeCell;
 2usecrate::Cell;
 3
 4#[derive(Clone,Copy)]
 5enumRefState{
 6Unshared,
 7Shared(usize),
 8Exclusive,
 9}
10
11pubstructRefCell{
12value:UnsafeCell,
13state:Cell,
14}
15
16implRefCell{
17pubfnnew(value:T)->Self{
18Self{
19value:UnsafeCell::new(value),
20state:Cell::new(RefState::Unshared),
21}
22}
23
24pubfnborrow(&self)->Option<&T>{
25None
26}
27
28pubfnborrow_mut(&self)->Option<&mut?T>{
29None
30}
31}

這是RefCell 最基本的API。borrow和borrow_mut方法的返回值使用Option,是因?yàn)槿绻ㄟ^(guò)borrow_mut獲取可變引用,則通過(guò)borrow獲取的共享引用返回None,反之亦然。

RecCell的引用狀態(tài)有三種,分別是非共享狀態(tài)(Unshared)、共享狀態(tài)(Shared)、獨(dú)占狀態(tài),使用enum來(lái)表示。其中共享狀態(tài)包含了一個(gè)引用計(jì)數(shù)器,類型為usize。

引用狀態(tài)我們使用了上面剛完成的Cell進(jìn)行包裝,是因?yàn)樾枰褂脙?nèi)部可變性來(lái)改變狀態(tài)。

下面來(lái)完成borrow和borrow_mut方法:

 1pubfnborrow(&self)->Option<&T>{
 2matchself.state.get(){
 3//當(dāng)前狀態(tài)如果是非共享狀態(tài),則設(shè)置引用狀態(tài)為共享狀態(tài)
 4RefState::Unshared=>{
 5self.state.set(RefState::Shared(1));
 6Some(unsafe{&*self.value.get()})
 7},
 8//當(dāng)前狀態(tài)如果是共享狀態(tài),則引用計(jì)數(shù)加1
 9RefState::Shared(n)=>{
10self.state.set(RefState::Shared(n+1));
11Some(unsafe{&*self.value.get()})
12},
13//當(dāng)前狀態(tài)如果是獨(dú)占狀態(tài),則返回None
14RefState::Exclusive=>None,
15}
16}
17
18pubfnborrow_mut(&self)->Option<&mut?T>{
19//引用狀態(tài)既不是共享狀態(tài),也不是獨(dú)占狀態(tài),才能設(shè)置為獨(dú)占狀態(tài)。
20ifletRefState::Unshared=self.state.get(){
21self.state.set(RefState::Exclusive);
22Some(unsafe{&mut*self.value.get()})
23}else{
24None
25}
26}
現(xiàn)在有個(gè)問(wèn)題,共享狀態(tài)的引用計(jì)數(shù)只有增沒(méi)有減,下面增加兩個(gè)類型來(lái)完善RefCell
 1/**
 2*包裝RefCell的共享引用struct
 3*/
 4pubstructRef<'refcell,?T>{
 5refcell:&'refcellRefCell,
 6}
 7
 8implDropforRef<'_,?T>{
 9//超出作用域范圍時(shí),共享引用狀態(tài)的變化
10fndrop(&mutself){
11matchself.refcell.state.get(){
12RefState::Unshared|RefState::Exclusive=>unreachable!(),
13RefState::Shared(1)=>{
14self.refcell.state.set(RefState::Unshared);
15},
16RefState::Shared(n)=>{
17self.refcell.state.set(RefState::Shared(n-1));
18}
19}
20}
21}
22
23implstd::DerefforRef<'_,?T>{
24typeTarget=T;
25
26//解引用時(shí)直接返回T的引用
27fnderef(&self)->&Self::Target{
28unsafe{&*self.refcell.value.get()}
29}
30}
 1/**
 2*包裝RefCell的可變引用struct
 3*/
 4pubstructRefMut<'refcell,?T>{
 5refcell:&'refcellRefCell,
 6}
 7
 8implDropforRefMut<'_,?T>{
 9//超出作用域范圍時(shí),獨(dú)占引用狀態(tài)的變化
10fndrop(&mutself){
11matchself.refcell.state.get(){
12RefState::Unshared|RefState::Shared(_)=>unreachable!(),
13RefState::Exclusive=>{
14self.refcell.state.set(RefState::Unshared);
15}
16}
17}
18}
19
20implstd::DerefforRefMut<'_,?T>{
21typeTarget=T;
22
23//解引用時(shí)直接返回T的引用
24fnderef(&self)->&Self::Target{
25unsafe{&*self.refcell.value.get()}
26}
27}
28
29implstd::DerefMutforRefMut<'_,?T>{
30//解引用時(shí)直接返回T的可變引用
31fnderef_mut(&mutself)->&mutSelf::Target{
32unsafe{&mut*self.refcell.value.get()}
33}
34}
RefCell的borrow和borrow_mut方法的返回值也需要做相應(yīng)的修改:
 1pubfnborrow(&self)->Option>{
 2matchself.state.get(){
 3//當(dāng)前狀態(tài)如果是非共享狀態(tài),則設(shè)置引用狀態(tài)為共享狀態(tài)
 4RefState::Unshared=>{
 5self.state.set(RefState::Shared(1));
 6Some(Ref{refcell:self})
 7},
 8//當(dāng)前狀態(tài)如果是共享狀態(tài),則引用計(jì)數(shù)加1
 9RefState::Shared(n)=>{
10self.state.set(RefState::Shared(n+1));
11Some(Ref{refcell:self})
12},
13//當(dāng)前狀態(tài)如果是獨(dú)占狀態(tài),則返回None
14RefState::Exclusive=>None,
15}
16}
17
18pubfnborrow_mut(&self)->Option>{
19//引用狀態(tài)既不是共享狀態(tài),也不是獨(dú)占狀態(tài),才能設(shè)置為獨(dú)占狀態(tài)。
20ifletRefState::Unshared=self.state.get(){
21self.state.set(RefState::Exclusive);
22Some(RefMut{refcell:self})
23}else{
24None
25}
26}
通過(guò)我們自己實(shí)現(xiàn)的Cell,RefCell的過(guò)程,我們了解了智能指針為什么需要實(shí)現(xiàn)Drop、Deref和DerefMut特征及內(nèi)部可變性的原理。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 計(jì)數(shù)器
    +關(guān)注

    關(guān)注

    32

    文章

    2253

    瀏覽量

    94281
  • 文件
    +關(guān)注

    關(guān)注

    1

    文章

    561

    瀏覽量

    24671
  • 指針
    +關(guān)注

    關(guān)注

    1

    文章

    478

    瀏覽量

    70491
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68231
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    228

    瀏覽量

    6542

原文標(biāo)題:CRust學(xué)習(xí)筆記:智能指針和內(nèi)部可變性

文章出處:【微信號(hào):Rust語(yǔ)言中文社區(qū),微信公眾號(hào):Rust語(yǔ)言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Windows -編程-變量和可變性

    Windows -編程-變量和可變性默認(rèn)情況下變量是不可變的。這是 Rust 為您提供的眾多推動(dòng)之一,您可以利用 Rust 提供的安全性和簡(jiǎn)單的并發(fā)性來(lái)編寫代碼。但是,您仍然可以選擇使變量可變
    發(fā)表于 08-24 14:27

    Windows -編程-變量和可變性-陰影

    Windows -編程-變量和可變性-陰影正如您 在第 2 章“比較猜測(cè)與秘密數(shù)字”部分的猜謎游戲教程中所見(jiàn),您可以聲明一個(gè)與前一個(gè)變量同名的新變量。Rustaceans 說(shuō)第一個(gè)變量被第二個(gè)變量
    發(fā)表于 08-24 14:35

    人工智能要面對(duì)的風(fēng)險(xiǎn)

    專注于學(xué)習(xí)可變性。即加強(qiáng)戰(zhàn)略與作戰(zhàn)思維并學(xué)習(xí)技能以應(yīng)對(duì)環(huán)境變化。
    的頭像 發(fā)表于 06-24 09:43 ?2112次閱讀

    Windows編程之變量和可變性綜述

    Windows編程之變量和可變性綜述
    發(fā)表于 08-24 14:22 ?3次下載

    Windows編程之變量與可變性詳解

    Windows編程之變量與可變性詳解
    發(fā)表于 08-24 14:52 ?8次下載

    單片機(jī)學(xué)習(xí)筆記————指針的第三大好處,指針作為數(shù)組在函數(shù)中的輸出接口

    單片機(jī)學(xué)習(xí)筆記————指針的第三大好處,指針作為數(shù)組在函數(shù)中的輸出接口
    發(fā)表于 11-26 10:51 ?1次下載
    單片機(jī)<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>————<b class='flag-5'>指針</b>的第三大好處,<b class='flag-5'>指針</b>作為數(shù)組在函數(shù)中的輸出接口

    單片機(jī)學(xué)習(xí)筆記————指針的第二大好處,指針作為數(shù)組在函數(shù)中的輸入接口

    單片機(jī)學(xué)習(xí)筆記————指針的第二大好處,指針作為數(shù)組在函數(shù)中的輸入接口
    發(fā)表于 11-26 10:51 ?7次下載
    單片機(jī)<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>————<b class='flag-5'>指針</b>的第二大好處,<b class='flag-5'>指針</b>作為數(shù)組在函數(shù)中的輸入接口

    CRust學(xué)習(xí)筆記:生命周期-1

    本系列文章是Jon Gjengset發(fā)布的CRust of Rust系列視頻的學(xué)習(xí)筆記,CRust of Rust是一系列持續(xù)更新的Rust中級(jí)教程。
    的頭像 發(fā)表于 12-19 09:33 ?826次閱讀

    CRust學(xué)習(xí)筆記:生命周期-2

    本系列文章是Jon Gjengset發(fā)布的CRust of Rust系列視頻的學(xué)習(xí)筆記,CRust of Rust是一系列持續(xù)更新的Rust中級(jí)教程。
    的頭像 發(fā)表于 12-19 09:34 ?821次閱讀

    CRust學(xué)習(xí)筆記:聲明宏

    本系列文章是Jon Gjengset發(fā)布的CRust of Rust系列視頻的學(xué)習(xí)筆記,CRust of Rust是一系列持續(xù)更新的Rust中級(jí)教程。
    的頭像 發(fā)表于 01-06 14:37 ?781次閱讀

    python字符串序列操作和不可變性

    初識(shí)python字符串序列操作和不可變性。python字符串序列操作為序列通用操作,python字符串不可變性是對(duì)字符串的操作不會(huì)改變?cè)甲址?/div>
    的頭像 發(fā)表于 02-23 15:01 ?822次閱讀

    rust語(yǔ)言基礎(chǔ)學(xué)習(xí): 智能指針之Cow

    Rust中與借用數(shù)據(jù)相關(guān)的三個(gè)trait: Borrow, BorrowMut和ToOwned。理解了這三個(gè)trait之后,再學(xué)習(xí)Rust中能夠?qū)崿F(xiàn)寫時(shí)克隆的智能指針Cow。
    的頭像 發(fā)表于 05-22 16:13 ?2842次閱讀

    面對(duì)不斷增加的設(shè)計(jì)可變性,提高穩(wěn)健性并最大限度地減少過(guò)度悲觀情緒

    長(zhǎng)期以來(lái),半導(dǎo)體一直根據(jù)最壞情況的工藝、電壓和溫度(PVT)進(jìn)行指定。在設(shè)計(jì)階段,設(shè)計(jì)人員必須平衡性能與功耗和面積(PPA),努力實(shí)現(xiàn)所需的每瓦性能目標(biāo)。為了評(píng)估可變性對(duì)電路性能的影響,設(shè)計(jì)人員采用
    的頭像 發(fā)表于 05-24 16:37 ?506次閱讀
    面對(duì)不斷增加的設(shè)計(jì)<b class='flag-5'>可變性</b>,提高穩(wěn)健性并最大限度地減少過(guò)度悲觀情緒

    C++智能指針的底層實(shí)現(xiàn)原理

    C++智能指針的頭文件: #include 1. shared_ptr: 智能指針從本質(zhì)上來(lái)說(shuō)是一個(gè)模板類,用類實(shí)現(xiàn)對(duì)指針對(duì)象的管理。 template class shared_ptr
    的頭像 發(fā)表于 11-09 14:32 ?686次閱讀
    C++<b class='flag-5'>智能指針</b>的底層實(shí)現(xiàn)原理

    硅片制造的光刻設(shè)置和工藝可變性假設(shè)

    電子發(fā)燒友網(wǎng)站提供《硅片制造的光刻設(shè)置和工藝可變性假設(shè).pdf》資料免費(fèi)下載
    發(fā)表于 06-25 14:23 ?0次下載