< 返回版块

xuejianxinokok 发表于 2024-09-09 10:15

Tags:refcell

在 https://rustx-labs.github.io/effective-rust-cn/chapter_1/item8-references&pointer.html 这本书中第8条


use std::cell::RefCell;
let rc: RefCell<u64> = RefCell::new(42);
let b1 = rc.borrow();
let b2 = rc.borrow(); 


其中的 b1,b2 为什么会画成胖指针?


Ext Link: https://rustx-labs.github.io/effective-rust-cn/chapter_1/item8-references&pointer.html

评论区

写评论
Bai-Jinlin 2024-09-11 12:11

设计成两个指针就是空间换时间并且简化设计,设计成一个指针那deref实现就需要两次解引用,实在没必要。

LazyBoy 2024-09-10 17:19

因为RefCell是在运行时检测共享和可变性的,所以borrow借用时,还需要保留借用状态指针吧,以便在自动归还(drop)时,可以修改RefCell的借用状态,这部分就需要第二个指针。 有一个掩耳盗铃的方式[doge]可以这样写:

let x = RefCell::new(());
let b = &*x.borrow();
println!("This is borrowed : {:?}", b);

但是还是会有一个匿名的Ref对象存在于整个借用作用域内,而且再也没法手动去drop它了[doge]只能离开作用域自动释放

👇
xuejianxinokok: 为什么会这样设计? 一个指针搞不定吗?

作者 xuejianxinokok 2024-09-10 15:11

pub fn borrow(&self) -> Ref<'_, T>

是返回

pub struct Ref<'b, T: ?Sized + 'b> {
    // NB: we use a pointer instead of `&'b T` to avoid `noalias` violations, because a
    // `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
    // `NonNull` is also covariant over `T`, just like we would have with `&T`.
    value : NonNull<T>,            //指向值
    borrow: BorrowRef<'b>,         //指向引用计数
}


type BorrowFlag = isize;
struct BorrowRef<'b> {
    borrow: &'b Cell<BorrowFlag>,  //可修改的引用计数
}

作者 xuejianxinokok 2024-09-10 10:17

为什么会这样设计? 一个指针搞不定吗?

--
👇
Neutron3529: 查看源码可知,.borrow()返回的是一个 Ref<'_>对象,Ref<'_>的布局就是俩指针,一个指向value: NonNull<T>,另一个指向borrow: BorrowRef<'b>

进一步的搜索可知

type BorrowFlag = isize;
struct BorrowRef<'b> {
    borrow: &'b Cell<BorrowFlag>,
}

因此这里的borrow是俩指针

aj3n 2024-09-09 13:19

因为Ref/RefMut需要支持map_split把一个Ref/RefMut拆成多个Ref/RefMut,所以引用计数指针和Deref指针要分开两个字段,不然一个指向RefCell的指针加上固定偏移就可以了;

Neutron3529 2024-09-09 11:51

查看源码可知,.borrow()返回的是一个 Ref<'_>对象,Ref<'_>的布局就是俩指针,一个指向value: NonNull<T>,另一个指向borrow: BorrowRef<'b>

进一步的搜索可知

type BorrowFlag = isize;
struct BorrowRef<'b> {
    borrow: &'b Cell<BorrowFlag>,
}

因此这里的borrow是俩指针

1 共 6 条评论, 1 页