与 rust RefCell<T> 和 Ref 相关的问题

questions related to rust RefCell<T> and Ref

提问人:Dennis 提问时间:8/4/2023 最后编辑:Dennis 更新时间:8/4/2023 访问量:43

问:

我正在努力解决为什么下面的代码无法编译。我正在尝试创建一个具有两个节点的双链表。然后从子节点指针访问父节点的值。

use std::cell::RefCell;
use std::rc::{Rc, Weak};

struct Node {
    val : i32,
    parent : RefCell<Option<Weak<Node>>>,
    child : RefCell<Option<Rc<Node>>>,
}

fn main() {
    let child_node = Node {
        val : 1,
        parent : RefCell::new(None),
        child : RefCell::new(None),
    };
    let child_node_ptr = Rc::new(child_node);
    
    let parent_node = Node {
        val : 2,
        parent : RefCell::new(None),
        child : RefCell::new(Some(Rc::clone(&child_node_ptr))),
    };
    let parent_node_ptr = Rc::new(parent_node);
    
    *child_node_ptr.parent.borrow_mut() = Some(Rc::downgrade(&parent_node_ptr));
    
    // this line fails to compile
    match *child_node_ptr.parent.borrow() {
        None => {},
        Some(parent_weak_ptr) => {
            match parent_weak_ptr.upgrade() {
                None => {},
                Some(parent_rc_ptr) => {
                    println!("parent node value is {}", parent_rc_ptr.val);
                },
            };
        },
    };
}

注释的 like 归档进行编译,错误信息为:

error[E0507]: cannot move out of dereference of `Ref<'_, Option<std::rc::Weak<Node>>>`
  --> src/main.rs:30:11
   |
30 |     match *child_node_ptr.parent.borrow() {
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31 |         None => {},
32 |         Some(parent_weak_ptr) => {
   |              ---------------
   |              |
   |              data moved here
   |              move occurs because `parent_weak_ptr` has type `std::rc::Weak<Node>`, which does not implement the `Copy` trait

我的第一个问题是为什么会这样?我看的方式,类型推导如下:

child_node_ptr : Rc<Node>
child_node_ptr.parent : RefCell<Option<Weak<Node>>>
child_node_ptr.parent.borrow() : Ref<'_, T>  where T is Option<Weak<Node>>

现在由于 std::cell::Ref 也实现了基于 Rust 文档的 trait,取消引用应该给出 &T,Deref

*child_node_ptr.parent.borrow() : &Option<Weak<Node>>

但实际上,当我打印出字体时,它实际上是

*child_node_ptr.parent.borrow() : Option<Weak<Node>>

因此,这似乎与 rust doc 所说的关于其 Deref 实现的说法相矛盾。

fn deref(&self) -> &T
蚀参考 refcell

评论

1赞 cafce25 8/4/2023
尝试此操作时几乎是强制性的:链表太多
2赞 cafce25 8/4/2023
虽然 的签名是使用特征的实际取消引用的签名,但编译器在取消引用时通过在使用时添加取消引用来删除一层指针。deref&self -> &TDeref&self -> T
0赞 Dennis 8/4/2023
感谢 Deref Coercion 文档,这非常有帮助,它曾经是 deref 而不是裸露的。

答:

2赞 Dennis 8/4/2023 #1

我想出答案是,这是在与我们作斗争,而不是帮助我们。Deref coercion

*child_node_ptr.parent.borrow()

成为

*(child_node_ptr.parent.borrow().deref())

由于 ,则变为Deref coercion

*(&Option<Weak<Node>>)

并成为

Option<Weak<Node>>