了解克隆借用

问题描述

我对 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 惯用方法

编辑: 上面的例子可能过于缩小,并没有突出我遇到的实际问题。编写类似下面示例的内容的 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),};
    let augmenting_trees = vec![
        Tree::Node { l: Box::new(Tree::Leaf),Tree::Node { l: Box::new(Tree::Node { l: Box::new(Tree::Leaf),Tree::Node { l: 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 惯用方法?

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

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];
    let c = modify_and_snapshot(&mut v);
    dbg!(v,c);
}

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