【问题标题】:difference of std::cell::Ref<T> and &Tstd::cell::Ref<T> 和 &T 的区别
【发布时间】:2021-03-30 15:38:22
【问题描述】:

我需要使用 RefCell 实现特定签名的功能。任务是:给定二叉树中特定深度d的节点列表,推导出下一层d+1的节点列表。我有一个草稿解决方案,但由于以下错误而无法编译:

error[E0515]: cannot return value referencing local variable `node`
  --> src/lib.rs:31:5
   |
26 |         if let Some(child) = &node.left {
   |                               ---- `node` is borrowed here
...
31 |     new_level
   |     ^^^^^^^^^ returns a value referencing data owned by the current function

为什么我希望我的代码能够工作:我只对函数 next_level 中的引用进行操作,因此,拥有的引用输入向量将在其执行结束时被删除这一事实应该不是问题 - 我的值指向还活着。我认为 std::cell::Ref 相当于普通的 ref,除了借用规则是在运行时强制执行的。

如果我将输入 vec 从 Vec&lt;Ref&lt;TreeNode&gt;&gt; 更改为 Vec&lt;&amp;TreeNode&gt;,则相同的代码可以工作。为什么?两者有何不同?

完整代码:

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

// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}


fn next_level(lvl: Vec<Ref<TreeNode>>) -> Vec<Ref<TreeNode>> {
    let mut new_level = vec![];
    for node in lvl {
        if let Some(child) = &node.left {
            let rf = child.borrow();
            new_level.push(rf);
        }
    }
    new_level
}

【问题讨论】:

    标签: rust


    【解决方案1】:

    Ref 代码出错的原因是新的Ref 输入的Ref 内,因此两者Refs 必须存在使其有效。然而,这个函数只返回一个Ref,这就是它出错的原因。此外,您不能同时返回两个Refs,因为一个依赖于另一个。它使用&amp; 代码工作的原因是&amp; 不需要原始引用仍然存在以使其存在,因为原始引用在被销毁为@987654329 时不需要执行诸如运行代码之类的操作@ 会。

    我建议在这种情况下绕过Vec&lt;Rc&lt;RefCell&lt;TreeNode&gt;&gt;&gt;s:

    use std::cell::{RefCell, Ref};
    use std::rc::Rc;
    
    // Definition for a binary tree node.
    #[derive(Debug, PartialEq, Eq)]
    pub struct TreeNode {
        pub val: i32,
        pub left: Option<Rc<RefCell<TreeNode>>>,
        pub right: Option<Rc<RefCell<TreeNode>>>,
    }
    
    
    fn next_level(lvl: Vec<Rc<RefCell<TreeNode>>>) -> Vec<Rc<RefCell<TreeNode>>> {
        let mut new_level = vec![];
        for node in lvl {
            if let Some(child) = &node.borrow().left {
                new_level.push(child.clone());
            }
        }
        new_level
    }
    

    【讨论】:

    • 谢谢! child.clone() 是包含所有子节点的深层副本,还是只是 Rc 的副本?
    • 只是Rc的副本,所以很便宜。
    猜你喜欢
    • 2016-01-19
    • 2021-07-10
    • 2023-04-11
    • 2021-06-21
    • 2014-06-12
    • 2021-06-02
    • 2017-08-21
    • 2020-09-15
    • 1970-01-01
    相关资源
    最近更新 更多