【发布时间】:2021-05-01 18:20:50
【问题描述】:
尽管我了解 Rust 的内存安全方法、所有权概念,并且对一般引用没有任何问题,但我仍在努力弄清楚 Rust 想要我如何解决一个看似微不足道的问题。
此代码是一个最小示例。
一个结构:
pub struct S {
value: Option<i8>,
}
使用第一次计算一个值,然后返回存储的值的 getter:
use rand::Rng;
impl S {
fn get_value(&mut self) -> i8 {
if let Some(v) = self.value {
return v;
}
let v = rand::thread_rng().gen::<i8>();
self.value = Some(v);
v
}
}
当然,get_value() 需要一个可变引用 &mut self,因为它修改了 self。
当我想根据get_value() 的结果对S 的引用向量进行排序时,这种可变性是我苦苦挣扎的根源。因为要按get_value()排序,所以sort_by使用的比较函数需要可变引用。
我的第一次尝试:
fn main() {
let mut a = S {value: None};
let mut b = S {value: None};
let mut c = S {value: None};
let mut v = vec![&mut a, &mut b, &mut c];
v.sort_by( |a, b| a.get_value().cmp(&b.get_value()) );
}
投掷:
error[E0596]: cannot borrow `**a` as mutable, as it is behind a `&` reference
--> src/main.rs:27:20
|
27 | v.sort_by( |a, b| a.get_v().cmp(&b.get_v()) );
| - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| |
| help: consider changing this to be a mutable reference: `&mut &mut S`
我最初的想法是,首先拥有一个可变引用向量将允许比较函数使用可变引用。然而,我的 getter 函数借用了可变引用的可变引用,这就是错误显示 cannot borrow '**a' 的原因。
帮助建议更改|a,b|,使其成为&mut &mut S 引用。
&mut &mut 和 &&mut 一样吗?
这是否意味着我应该将其更改为|mut a:&&mut S, mut b:&&mut S|?
【问题讨论】:
-
&&mut x不能被变异,就好像它可以一样,您可以拆分可变引用,从而导致竞争条件。可悲的是,排序仅在 Rust 中是不可变的引用,因为如果值在排序期间发生变化,它可能会扰乱整个过程。您可能需要考虑使用std::cell::Cell之类的东西来实现内部可变性,因为您的案例是完全安全的(一旦获得一个值,它就永远不会改变)。 -
如果您的值在被访问之前未创建,然后没有更改,请考虑使用
OnceCell
标签: rust reference closures borrow-checker borrowing