本系列文章是Jon Gjengset發(fā)布的CRust of Rust系列視頻的學(xué)習(xí)筆記,CRust of Rust是一系列持續(xù)更新的Rust中級(jí)教程。
我們將通過(guò)手動(dòng)實(shí)現(xiàn)Cell
新建一個(gè)項(xiàng)目:
cargo new --lib pointers手動(dòng)實(shí)現(xiàn)Cell
1modcell;在cell.rs中寫入如下代碼:
1usestd::UnsafeCell; 2 3pubstructCell{ 4value:UnsafeCell , 5} 6 7impl Cell { 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
在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
在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 16impl RefCell { 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
RecCell
引用狀態(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 8impl DropforRef<'_,?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 23impl std::DerefforRef<'_,?T>{ 24typeTarget=T; 25 26//解引用時(shí)直接返回T的引用 27fnderef(&self)->&Self::Target{ 28unsafe{&*self.refcell.value.get()} 29} 30}
1/** 2*包裝RefCellRefCell的可變引用struct 3*/ 4pubstructRefMut<'refcell,?T>{ 5refcell:&'refcellRefCell , 6} 7 8impl DropforRefMut<'_,?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 20impl std::DerefforRefMut<'_,?T>{ 21typeTarget=T; 22 23//解引用時(shí)直接返回T的引用 24fnderef(&self)->&Self::Target{ 25unsafe{&*self.refcell.value.get()} 26} 27} 28 29impl std::DerefMutforRefMut<'_,?T>{ 30//解引用時(shí)直接返回T的可變引用 31fnderef_mut(&mutself)->&mutSelf::Target{ 32unsafe{&mut*self.refcell.value.get()} 33} 34}
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通過(guò)我們自己實(shí)現(xiàn)的Cell>{ 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}
-
計(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)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論