一次不能多次借用 `x` 作为可变变量 [英] Cannot borrow `x` as mutable more than once at a time

查看:49
本文介绍了一次不能多次借用 `x` 作为可变变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中(playground):

struct Node {
    datum: &'static str,
    edges: Vec<Node>,
}

fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node {
    node.edges.push(Node {
        datum: data,
        edges: Vec::new(),
    });
    &node.edges[node.edges.len() - 1] // return just added one
}

fn traverse<F>(root: &Node, callback: &F)
where
    F: Fn(&'static str),
{
    callback(root.datum);
    for node in &root.edges {
        traverse(node, callback);
    }
}

fn main() {
    let mut tree = Node {
        datum: "start",
        edges: Vec::new(),
    };

    let lvl1 = add(&mut tree, "level1");

    traverse(&mut tree, &|x| println!("{:}", x)); //I actually don't need mutability here
}

我有这个错误:

error[E0499]: cannot borrow `tree` as mutable more than once at a time
  --> src/main.rs:32:19
   |
30 |     let lvl1 = add(&mut tree, "level1");
   |                         ---- first mutable borrow occurs here
31 | 
32 |     traverse(&mut tree, &|x| println!("{:}", x)); //I actually don't need mutability here
   |                   ^^^^ second mutable borrow occurs here
33 | }
   | - first borrow ends here

我的问题似乎与为什么 Rust 想要一次多次借用一个可变的变量?,但我不确定.如果是这样,这种情况有解决方法吗?

My question seems to be very similar to Why does Rust want to borrow a variable as mutable more than once at a time?, but I'm not sure. If so, is there a workaround for this case?

推荐答案

发生这种情况的原因是 add 的定义方式:

This happens because of how add is defined:

fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node

这里指定结果引用的生命周期应该等于传入引用的生命周期.唯一可能的方式(不安全代码除外)是结果引用以某种方式从传入引用派生,例如,它引用传入引用指向的对象内部的某些字段:>

Here it is specified that the lifetime of the resulting reference should be equal to the lifetime of the incoming reference. The only way it is possible (except for unsafe code) is that the resulting reference is somehow derived from the incoming reference, for example, it references some field inside the object the incoming reference points at:

struct X {
    a: u32,
    b: u32,
}

fn borrow_a<'a>(x: &'a mut X) -> &'a mut u32 {
    &mut x.a
}

但是,编译器没有没有方法可以通过仅查看函数签名(通常是编译使用此函数的代码时它唯一可以做的事情).因此,它无法知道以下代码在技术上是正确的:

However, there is no way for the compiler to know what exactly from the incoming structure is borrowed by looking only at the function signature (which, in general, is the only thing it can do when compiling code which uses this function). Therefore, it can't know that the following code is technically correct:

let mut x = X { a: 1, b: 2 };
let a = borrow_a(&mut x);
let b = &mut x.b;

我们知道 ab 是不相交的,因为它们指向结构的不同部分,但是编译器不知道因为 borrow_a 的签名中没有任何东西可以暗示它(而且不可能,Rust 不支持它).

We know that a and b are disjoint because they point at different parts of the structure, but the compiler can't know that because there is nothing in borrow_a's signature which would suggest it (and there can't be, Rust does not support it).

因此,编译器可以做的唯一明智的事情是考虑借用整个 x 直到 borrow_a() 被丢弃.否则就有可能为相同的数据创建两个可变引用,这违反了 Rust 别名保证.

Therefore, the only sensible thing the compiler could do is to consider the whole x to be borrowed until the reference returned by borrow_a() is dropped. Otherwise it would be possible to create two mutable references for the same data, which is a violation of Rust aliasing guarantees.

注意以下代码是正确的:

Note that the following code is correct:

let mut x = X { a: 1, b: 2 };
let a = &mut x.a;
let b = &mut x.b;

这里编译器可以看到 ab 永远不会指向相同的数据,即使它们确实指向相同的结构内部.

Here the compiler can see that a and b never point to the same data, even though they do point inside of the same structure.

对此没有解决方法,唯一的解决方案是重构代码,使其不具有这种借用模式.

There is no workaround for this, and the only solution would be to restructure the code so it doesn't have such borrowing patterns.

这篇关于一次不能多次借用 `x` 作为可变变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆