fn change(a: &mut i32, b: &mut i32) {
let c = *a;
*a = *b;
*b = c;
}
fn main() {
let mut v = vec![1, 2, 3];
change(&mut v[0], &mut v[1]);
}
当我编译上面的代码时,它有错误:
error[E0499]: cannot borrow `v` as mutable more than once at a time
--> src/main.rs:9:32
|
9 | change(&mut v[0], &mut v[1]);
| - ^ - first borrow ends here
| | |
| | second mutable borrow occurs here
| first mutable borrow occurs here
为什么编译器禁止它?v[0]
和v[1]
占用不同的内存位置,所以一起使用并不危险。如果我遇到这个问题该怎么办?
9条答案
按热度按时间rqdpfwrv1#
你可以用
split_at_mut()
来解决这个问题:不幸的是,编译器还不能识别无数安全的事情。
split_at_mut()
就像这样,一个用unsafe
块内部实现的安全抽象。对于这个问题,我们也可以这样做。下面是我在代码中使用的一些东西,我无论如何都需要将这三种情况分开(I:索引超出界限,II:指数相等,III:单独的指数)。
5us2dqdw2#
从Rust1.26开始,模式匹配可以在切片上完成,只要你没有巨大的索引,并且你的索引在编译时是已知的,你就可以使用它。
qmelpv7a3#
Rust的借用规则需要在编译时检查,这就是为什么像可变借用
Vec
的一部分这样的事情是一个很难解决的问题(如果不是不可能的话),也是为什么Rust不可能做到这一点。因此,当你做
&mut v[i]
这样的操作时,它会可变地借用整个向量。想象一下我做了一件事
在这里,我创建了一个对象
guard
,它在内部存储了一个对v[i]
的可变引用,并在调用do_job()
时对其执行一些操作。与此同时,我做了一些改变
v[j]
的事情。guard
保存了一个可变引用,该引用应该保证没有其他东西可以修改v[i]
。在本例中,只要i
不同于j
,一切都很好;如果两个值相等,则这是对借用规则的巨大违反。由于编译器无法保证
i != j
,因此禁止使用。这是一个简单的例子,但类似的情况是大量的,这就是为什么这样的访问会可变地借用整个容器。再加上编译器实际上对
Vec
的内部结构了解不够,无法确保此操作即使在i != j
的情况下也是安全的。在您的具体情况下,您可以查看
Vec
上可用的swap(..)
方法,该方法执行您正在手动实现的交换。在更一般的情况下,你可能需要一个其他的容器,可能的方法是把
Vec
的所有值 Package 成一个内部可变的类型,比如Cell
或RefCell
,或者甚至使用一个完全不同的容器,就像@llogiq在他对par-vec
的回答中建议的那样。new9mtju4#
[T]::iter_mut()
方法返回一个迭代器,它可以为切片中的每个元素生成一个可变引用。其他集合也有iter_mut
方法。这些方法通常封装不安全的代码,但它们的接口是完全安全的。下面是一个通用的扩展特性,它在切片上添加了一个方法,该方法通过索引返回对两个不同项的可变引用:
a1o7rhls5#
在最近的夜生活中,有
get_many_mut()
:kqlmhetl6#
你不能对同一个数据做两个可变的引用。这是借用检查器明确禁止的,以防止并发修改。但是你可以使用
unsafe
块绕过借用检查器。虽然在您的例子中
v[0]
和v[1]
是明显分开的块,但这并不经得起认真的审查。如果v
是某种称为NullMap
的Map,它将所有元素Map到单个字段呢?编译器如何知道在Vec
操作中v[0];v[1];
是安全的,而在NullMap
中不是?如果你想交换数组中的两个元素,为什么不选择
slice::swap
呢?另外
v
需要是mut
,因为你要改变向量,一个不变的版本会克隆它并在它上面执行交换。z9ju0rcb7#
在@bluss给出的答案的基础上,我们可以使用
split_at_mut()
创建一个函数,将向量的可变借位转换为向量元素的可变借位的向量:然后,你可以用它来获得一个绑定,让你一次改变原始Vec的许多项,即使你正在迭代它们(如果你在循环中通过索引访问它们,而不是通过任何迭代器):
qmb5sa228#
问题是
&mut v[…]
首先可变地借用v
,然后将对元素的可变引用提供给change函数。This reddit评论有一个解决你的问题的方法。
编辑:谢谢你的提醒,Shepmaster. par-vec是一个库,它允许可变地借用vec的分离分区。
bzzcjhmw9#
我将我的每日效用发布到crate.io.Link to the doc。
你可以这样使用它
这是对下面代码的简单 Package ,很合理,但它要求两个索引在运行时不同。
或者,您可以使用不会对
mut_twice
造成混乱的方法