电子说
本系列文章是Jon Gjengset发布的CRust of Rust系列视频的学习笔记,CRust of Rust是一系列持续更新的Rust中级教程。
我们将通过手动实现Cell
新建一个项目:
cargo new --lib pointers手动实现Cell
1mod cell;在cell.rs中写入如下代码:
1use std::UnsafeCell; 2 3pub struct Cell{ 4 value: UnsafeCell , 5} 6 7impl Cell { 8 pub fn new(value: T) -> Self { 9 Cell { 10 value: UnsafeCell::new(value), 11 } 12 } 13 14 pub fn set(&self, value: T) { 15 unsafe { 16 *self.value.get() = value 17 }; 18 } 19 20 pub fn get(&self) -> T where T: Copy{ 21 unsafe { 22 *self.value.get() 23 } 24 } 25}
实现内部可变性需要一个特殊的cell类型,叫作UnsafeCell
在set和get方法中需要获取类型的原生的指针,因此需要使用unsafe块。由于UnsafeCell实现了!Sync trait,表示不能安全的跨线程共享引用。
测试代码如下:
1#[cfg(test)] 2mod test { 3 use super::Cell; 4 5 #[test] 6 fn cell_test() { 7 let mut x = Cell::new(42); 8 let i = x.get(); 9 x.set(43); 10 11 assert_eq!(i, 42); 12 } 13}执行cargo test,测试通过。 手动实现RefCell
RefCell
在src目录下新建一个refcell.rs文件,然后在lib.rs中加入:
1mod refcell;在refcell.rs中写入如下代码:
1use std::UnsafeCell; 2use crate::Cell; 3 4#[derive(Clone, Copy)] 5enum RefState { 6 Unshared, 7 Shared(usize), 8 Exclusive, 9} 10 11pub struct RefCell{ 12 value: UnsafeCell , 13 state: Cell , 14} 15 16impl RefCell { 17 pub fn new(value: T) -> Self { 18 Self { 19 value: UnsafeCell::new(value), 20 state: Cell::new(RefState::Unshared), 21 } 22 } 23 24 pub fn borrow(&self) -> Option<&T> { 25 None 26 } 27 28 pub fn borrow_mut(&self) -> Option<&mut T> { 29 None 30 } 31}
这是RefCell
RecCell
引用状态我们使用了上面刚完成的Cell进行包装,是因为需要使用内部可变性来改变状态。
下面来完成borrow和borrow_mut方法:
1pub fn borrow(&self) -> Option<&T> { 2 match self.state.get() { 3 // 当前状态如果是非共享状态,则设置引用状态为共享状态 4 RefState::Unshared => { 5 self.state.set(RefState::Shared(1)); 6 Some(unsafe {&*self.value.get()}) 7 }, 8 // 当前状态如果是共享状态,则引用计数加1 9 RefState::Shared(n) => { 10 self.state.set(RefState::Shared(n + 1)); 11 Some(unsafe {&*self.value.get()}) 12 }, 13 // 当前状态如果是独占状态,则返回None 14 RefState::Exclusive => None, 15 } 16} 17 18pub fn borrow_mut(&self) -> Option<&mut T> { 19 // 引用状态既不是共享状态,也不是独占状态,才能设置为独占状态。 20 if let RefState::Unshared = self.state.get() { 21 self.state.set(RefState::Exclusive); 22 Some(unsafe {&mut *self.value.get()}) 23 }else { 24 None 25 } 26}现在有个问题,共享状态的引用计数只有增没有减,下面增加两个类型来完善RefCell
1/** 2 * 包装RefCell的共享引用struct 3 */ 4pub struct Ref<'refcell, T> { 5 refcell: &'refcell RefCell , 6} 7 8impl Drop for Ref<'_, T> { 9 // 超出作用域范围时,共享引用状态的变化 10 fn drop(&mut self) { 11 match self.refcell.state.get() { 12 RefState::Unshared | RefState::Exclusive => unreachable!(), 13 RefState::Shared(1) => { 14 self.refcell.state.set(RefState::Unshared); 15 }, 16 RefState::Shared(n) => { 17 self.refcell.state.set(RefState::Shared(n - 1)); 18 } 19 } 20 } 21} 22 23impl std::Deref for Ref<'_, T> { 24 type Target = T; 25 26 // 解引用时直接返回 T 的引用 27 fn deref(&self) -> &Self::Target { 28 unsafe {&*self.refcell.value.get()} 29 } 30}
1/** 2 * 包装RefCellRefCell的可变引用struct 3 */ 4pub struct RefMut<'refcell, T> { 5 refcell: &'refcell RefCell , 6} 7 8impl Drop for RefMut<'_, T> { 9 // 超出作用域范围时,独占引用状态的变化 10 fn drop(&mut self) { 11 match self.refcell.state.get() { 12 RefState::Unshared | RefState::Shared(_) => unreachable!(), 13 RefState::Exclusive => { 14 self.refcell.state.set(RefState::Unshared); 15 } 16 } 17 } 18} 19 20impl std::Deref for RefMut<'_, T> { 21 type Target = T; 22 23 // 解引用时直接返回 T 的引用 24 fn deref(&self) -> &Self::Target { 25 unsafe {&*self.refcell.value.get()} 26 } 27} 28 29impl std::DerefMut for RefMut<'_, T> { 30 // 解引用时直接返回 T 的可变引用 31 fn deref_mut(&mut self) -> &mut Self::Target { 32 unsafe {&mut *self.refcell.value.get()} 33 } 34}
1pub fn borrow(&self) -> Option> { 2 match self.state.get() { 3 // 当前状态如果是非共享状态,则设置引用状态为共享状态 4 RefState::Unshared => { 5 self.state.set(RefState::Shared(1)); 6 Some(Ref{refcell: self}) 7 }, 8 // 当前状态如果是共享状态,则引用计数加1 9 RefState::Shared(n) => { 10 self.state.set(RefState::Shared(n + 1)); 11 Some(Ref{refcell: self}) 12 }, 13 // 当前状态如果是独占状态,则返回None 14 RefState::Exclusive => None, 15 } 16} 17 18pub fn borrow_mut(&self) -> Option通过我们自己实现的Cell> { 19 // 引用状态既不是共享状态,也不是独占状态,才能设置为独占状态。 20 if let RefState::Unshared = self.state.get() { 21 self.state.set(RefState::Exclusive); 22 Some(RefMut{refcell: self}) 23 }else { 24 None 25 } 26}
全部0条评论
快来发表一下你的评论吧 !