在以下代码(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我的问题似乎与Why does Rust want to borrow a variable as mutable more than once at a time?非常相似,但我不确定。如果是这样,有没有解决这个问题的办法?
发布于 2015-07-08 13:20:51
这是由于add的定义方式造成的:
fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node这里指定结果引用的生存期应等于传入引用的生存期。唯一可能的方法(不安全代码除外)是结果引用以某种方式派生自传入引用,例如,它引用了传入引用所指向的对象内的某个字段:
struct X {
a: u32,
b: u32,
}
fn borrow_a<'a>(x: &'a mut X) -> &'a mut u32 {
&mut x.a
}但是,编译器无法通过只查看函数签名来确切知道传入结构中借用了什么(通常,这是编译使用此函数的代码时唯一能做的事情)。因此,它不能知道以下代码在技术上是正确的:
let mut x = X { a: 1, b: 2 };
let a = borrow_a(&mut x);
let b = &mut x.b;我们知道a和b是不相交的,因为它们指向结构的不同部分,但是编译器不能知道这一点,因为在borrow_a的签名中没有任何东西会暗示它(不可能有,Rust不支持它)。
因此,编译器能做的唯一明智的事情就是考虑借用整个x,直到删除borrow_a()返回的引用。否则,可能会为同一数据创建两个可变引用,这违反了Rust别名保证。
请注意,以下代码是正确的:
let mut x = X { a: 1, b: 2 };
let a = &mut x.a;
let b = &mut x.b;在这里,编译器可以看到a和b从不指向相同的数据,即使它们确实指向相同的结构内部。
这个问题没有变通的办法,唯一的解决方案是重新构造代码,这样它就不会有这样的借用模式。
发布于 2015-07-08 11:02:26
这种行为是合乎逻辑的。考虑一下什么
fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node意思是。
这表示&mut Node的生命周期等于其返回值的生命周期。因为您将返回值分配给一个名称,所以它会一直存在到作用域的末尾。因此,可变的借入也存在这么长的时间。
如果您可以很容易地丢弃返回值,请这样做。你可以把它扔到地板上:
let mut tree = Node {
datum: "start",
edges: Vec::new(),
};
add(&mut tree, "level1");
traverse(&mut tree, &|x| println!("{:}", x));或者,您可以使用词法作用域来约束它,而不必完全删除它。
如果你想借入返回值,而又不想让可变的借入保持那么长的时间,那么你可能不得不将函数一分为二。这是因为您无法从可变的borrow中借用返回值来执行此操作。
https://stackoverflow.com/questions/31281155
复制相似问题