无法移出“当前”,因为它是在从递归返回时借用的

Cannot move out of `current` because it is borrowed while returning from recursion

提问人:Erhan Bagdemir 提问时间:10/30/2023 最后编辑:Erhan Bagdemir 更新时间:10/30/2023 访问量:81

问:

让我们考虑一下我的存储结构,它包含 u16 中的键向量:

pub struct Storage {
    ...
    pub root: Option<RefCell<Node>>,
}


pub struct Node {
    pub keys: RefCell<Vec<u16>>,
    pub children: RefCell<Vec<Node>>,
}

在递归期间的某个时间点,作为调用遍历子项的子项并搜索提供的键,

pub fn search(&'a self, key: u16, current: Ref<'a, Node>) -> (usize, Ref<'a, Node>) {
    let keys = current.keys.borrow();
    for index in 0..keys.len() {
        if keys[index] == key && current.is_leaf() {
            return (index, current);
        }
    }
}

递归通过 return 语句终止。函数调用应返回匹配键和当前 Node 实例的索引,以便调用方可以进行一些修改。但是,rustc 正在抱怨它:

error[E0505]: cannot move out of `current` because it is borrowed
  --> src/index/btree.rs:87:36
   |
84 |             let keys = current.keys.borrow();
   |                        ------- borrow of `current` occurs here
...
87 |                     return (index, current);
   |                                    ^^^^^^^ move out of `current` occurs here
...
90 |         }
   |         - borrow might be used here, when `keys` is dropped and runs the destructor for type `Ref<'_, Vec<u16>>`

我知道该函数借用了第 84 行的键,只要“键”引用在附近,即直到它们在方法调用后被丢弃,但我的问题是在算法中处理这个问题的惯用方法是什么?尤其是在没有克隆对象的情况下,这对我来说听起来像是一种解决方法?

Rust 借用检查器

评论

1赞 Caesar 10/30/2023
你也许可以解决这个问题。但实际上,阅读了太多的链接列表,尤其是关于迭代器的章节。这是关于你在做什么,以及为什么这不是一个好主意。

答:

1赞 Michael Anderson 10/30/2023 #1

我想你一定从你的例子中遗漏了一些重要的东西。它不会按原样编译。

更改它以解决最明显的问题,并从传递切换到仅传递,然后它为我编译:Ref<'a, Node>&Node

use std::cell::RefCell;

pub struct Node {
    pub keys: RefCell<Vec<u16>>,
    pub children: RefCell<Vec<Node>>,
}

impl Node {
    fn is_leaf(&self) -> bool {
        todo!()
    }
}

pub fn search(key: u16, current: &Node) -> Option<(usize, &Node)> {
    let keys = current.keys.borrow();
    for index in 0..keys.len() {
        if keys[index] == key && current.is_leaf() {
            return Some((index, current));
        }
    }
    None
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f0ae75422458645b6521ac3803f0411c

评论

0赞 Erhan Bagdemir 10/30/2023
谢谢迈克尔。该方法之所以将 Refs 作为参数,是因为 Node 的所有者 Storage(即 Storage)的内部可变性。我更新了上面的代码片段。因此,搜索从根节点开始,该节点是 RefCell。你对更好的惯用设计有什么建议吗?
0赞 Chayim Friedman 10/31/2023
@ErhanBagdemir 一般来说,没有什么理由采取.您始终可以通过(重新借用)它来转换它。RefRef&&*
0赞 Michael Anderson 10/31/2023
@ErhanBagdemir创建一个最小的独立示例来演示该问题?(stackoverflow.com/help/minimal-reproducible-example)目前,代码中有太多其他错误,无法确定您要执行的操作。