本系列文章是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
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
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}
现在有个问题,共享状态的引用计数只有增没有减,下面增加两个类型来完善RefCell1/** 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文章
2306浏览量
97573 -
文件
+关注
关注
1文章
587浏览量
25917 -
指针
+关注
关注
1文章
484浏览量
71677 -
代码
+关注
关注
30文章
4941浏览量
73151 -
Rust
+关注
关注
1文章
240浏览量
7481
原文标题:CRust学习笔记:智能指针和内部可变性
文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
Windows -编程-变量和可变性
Windows -编程-变量和可变性-阴影
CRust学习笔记:生命周期-1
CRust学习笔记:生命周期-2
CRust学习笔记:声明宏
python字符串序列操作和不可变性
rust语言基础学习: 智能指针之Cow
面对不断增加的设计可变性,提高稳健性并最大限度地减少过度悲观情绪
C++智能指针的底层实现原理

CRust学习笔记:智能指针和内部可变性
评论