本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记,CRust of Rust是一系列持续更新的Rust中级教程。
我们将通过手动实现Cell
新建一个项目:
cargo new --lib pointers手动实现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}
实现内部可变性需要一个特殊的cell类型,叫作UnsafeCell
在set和get方法中需要获取类型的原生的指针,因此需要使用unsafe块。由于UnsafeCell实现了!Sync trait,表示不能安全的跨线程共享引用。
测试代码如下:
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}执行cargo test,测试通过。 手动实现RefCell
RefCell
在src目录下新建一个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
引用状态我们使用了上面刚完成的Cell进行包装,是因为需要使用内部可变性来改变状态。
下面来完成borrow和borrow_mut方法:
1pubfnborrow(&self)->Option<&T>{ 2matchself.state.get(){ 3//当前状态如果是非共享状态,则设置引用状态为共享状态 4RefState::Unshared=>{ 5self.state.set(RefState::Shared(1)); 6Some(unsafe{&*self.value.get()}) 7}, 8//当前状态如果是共享状态,则引用计数加1 9RefState::Shared(n)=>{ 10self.state.set(RefState::Shared(n+1)); 11Some(unsafe{&*self.value.get()}) 12}, 13//当前状态如果是独占状态,则返回None 14RefState::Exclusive=>None, 15} 16} 17 18pubfnborrow_mut(&self)->Option<&mut T>{ 19//引用状态既不是共享状态,也不是独占状态,才能设置为独占状态。 20ifletRefState::Unshared=self.state.get(){ 21self.state.set(RefState::Exclusive); 22Some(unsafe{&mut*self.value.get()}) 23}else{ 24None 25} 26}现在有个问题,共享状态的引用计数只有增没有减,下面增加两个类型来完善RefCell
1/** 2*包装RefCell的共享引用struct 3*/ 4pubstructRef<'refcell, T>{ 5refcell:&'refcellRefCell , 6} 7 8impl DropforRef<'_, T>{ 9//超出作用域范围时,共享引用状态的变化 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//解引用时直接返回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//超出作用域范围时,独占引用状态的变化 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//解引用时直接返回T的引用 24fnderef(&self)->&Self::Target{ 25unsafe{&*self.refcell.value.get()} 26} 27} 28 29impl std::DerefMutforRefMut<'_, T>{ 30//解引用时直接返回T的可变引用 31fnderef_mut(&mutself)->&mutSelf::Target{ 32unsafe{&mut*self.refcell.value.get()} 33} 34}
1pubfnborrow(&self)->Option>{ 2matchself.state.get(){ 3//当前状态如果是非共享状态,则设置引用状态为共享状态 4RefState::Unshared=>{ 5self.state.set(RefState::Shared(1)); 6Some(Ref{refcell:self}) 7}, 8//当前状态如果是共享状态,则引用计数加1 9RefState::Shared(n)=>{ 10self.state.set(RefState::Shared(n+1)); 11Some(Ref{refcell:self}) 12}, 13//当前状态如果是独占状态,则返回None 14RefState::Exclusive=>None, 15} 16} 17 18pubfnborrow_mut(&self)->Option通过我们自己实现的Cell>{ 19//引用状态既不是共享状态,也不是独占状态,才能设置为独占状态。 20ifletRefState::Unshared=self.state.get(){ 21self.state.set(RefState::Exclusive); 22Some(RefMut{refcell:self}) 23}else{ 24None 25} 26}
-
计数器
+关注
关注
32文章
2261浏览量
94955 -
文件
+关注
关注
1文章
570浏览量
24812 -
指针
+关注
关注
1文章
481浏览量
70601 -
代码
+关注
关注
30文章
4823浏览量
68991 -
Rust
+关注
关注
1文章
230浏览量
6650
原文标题:CRust学习笔记:智能指针和内部可变性
文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论