【问题标题】:Understanding clones borrow了解克隆借用
【发布时间】:2021-04-15 21:32:38
【问题描述】:

我对 rust 还很陌生,仍在学习 rust 所有权模型。我正在编写一段代码,其中我持有对数据结构中某个点的引用。我想存储此数据结构的多个副本,其中每个副本上的参考点包含不同的值。我(试图)通过创建对数据结构内部点的可变引用来解决这个问题,并在每次更新引用后创建原始数据结构的克隆。

我能够创建这个简单的示例,它类似于我正在尝试做的事情并产生相同的错误。

fn main() {
    let mut v = vec![1, 1, 1];
    let mut c = Vec::new();

    for i in &mut v {
        *i += 1;
        c.push(v.clone());
    }

    println!("{:?}", v);
}

产生以下错误

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
   --> src/main.rs:107:16
    |
105 |     for i in &mut v {
    |              ------
    |              |
    |              mutable borrow occurs here
    |              mutable borrow later used here
106 |         *i += 1;
107 |         c.push(v.clone());
    |                ^ immutable borrow occurs here

在方便的 rust book 的帮助下,我能够解释错误消息。我相信这告诉我,我不能同时拥有一个可变引用和一个不可变引用。迭代地创建数据结构的副本并更新所述数据结构中的引用的 rust 惯用方法是什么(或是否存在)?

编辑: 上面的例子可能太小了,没有突出我遇到的实际问题。编写类似以下示例的内容的惯用生锈方式是什么。

#[derive(Clone, Debug)]
enum Tree {
    Leaf,
    Node { l: Box<Tree>, r: Box<Tree>, },
}

fn main() {
    let mut tree = Tree::Node {
      l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
      r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
    };
    let augmenting_trees = vec![
        Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), },
        Tree::Node { l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), r: Box::new(Tree::Leaf), },
        Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), },
    ];

    let mut trees: Vec<Tree> = Vec::new();
    let leaf = find_some_leaf_in_tree(&mut tree);
    for augmenting_tree in augmenting_trees {
        *leaf = augmenting_tree;
        trees.push(tree.clone());
    }

    println!("trees: {:?}", trees);
}

fn find_some_leaf_in_tree<'a>(tree: &'a mut Tree) -> &'a mut Tree {
    match tree {
        Tree::Leaf => tree,
        Tree::Node { l, .. } => find_some_leaf_in_tree(l),
    }
}

【问题讨论】:

    标签: rust clone mutable borrow


    【解决方案1】:

    什么是(或是否存在)迭代创建数据结构副本并更新所述数据结构中的引用的 rust 惯用方法?

    一般的答案是“不要将参考用于您尝试使用参考的目的”。在这种情况下,您有一个向量,因此请使用索引而不是引用:

    fn main() {
        let mut v = vec![1, 1, 1];
        let mut c = Vec::new();
    
        for i in 0..v.len() {
            v[i] += 1;
            c.push(v.clone());
        }
    
        dbg!(v, c);
    }
    

    请注意,这并不意味着您完全不能使用引用。例如,代码可以用对v 的可变引用来编写:

    fn modify_and_snapshot(v: &mut Vec<u32>) -> Vec<Vec<u32>> {
        let mut c = Vec::new();
        for i in 0..v.len() {
            v[i] += 1;
            c.push(v.clone());
        }
        c
    }
    
    fn main() {
        let mut v = vec![1, 1, 1];
        let c = modify_and_snapshot(&mut v);
        dbg!(v, c);
    }
    

    必要条件是,当您要对v 进行快照时,您没有对小于所有v 的可变引用——您可以拥有整个向量,或者您可以对整个向量有一个可变引用,但是你不能对整个向量做任何事情,而对它的 part 的可变引用存在。

    【讨论】:

    • 感谢您的回答。所以在这种情况下不要使用引用是有道理的。我已经更新了我的答案以包含一个稍微复杂的示例,其中使用引用更有意义。生锈的惯用方式仍然是“不使用引用”吗?如果是这样,我如何在没有所述参考的情况下更新数据结构的一部分?提前感谢您的时间/关注。
    • @CasperLamboo 抽象的答案还是一样的。对于树的情况,我建议您回滚您的编辑并发布一个关于树特别的新问题,因为适用于树(或一般而言,包含递归的数据结构)的策略具有特定的特征.
    猜你喜欢
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 2020-09-17
    相关资源
    最近更新 更多