考虑这个玩具代码:
struct X {
x: usize,
times_accessed: usize,
}
impl X {
fn get(&mut self) -> usize {
self.times_accessed = self.times_accessed + 1;
self.x
}
}
struct Y {
y: usize,
max_access: usize,
option_x: Option<X>,
}
impl Y {
fn get_x(&mut self) -> Option<usize> {
match self.option_x {
Some(ref mut some_x) => {
let result = some_x.get();
if some_x.times_accessed == self.max_access {
self.option_x = None;
}
Some(result)
}
None => {
println!("option_x is not initialized! try calling Y::init_x");
None
}
}
}
fn init_x(&mut self, x_val: usize, max_allowed_access: usize) {
self.max_access = max_allowed_access;
self.option_x = Some(X {
x: x_val,
times_accessed: 0,
});
}
}
fn main() {
println!("hello world!");
}
我没有在 main 函数中使用 Y
,因为编译器不需要我这样做来指出借用检查器不会对 的实现感到满意>Y::get_x
:
error[E0506]: cannot assign to `self.option_x` because it is borrowed
--> src/main.rs:26:21
|
22 | Some(ref mut some_x) => {
| -------------- borrow of `self.option_x` occurs here
...
26 | self.option_x = None;
| ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.option_x` occurs here
我从借用检查员的角度理解这个问题,我可以想出一个非常简单的解决方法:将 some_x
中的值复制到 result
中(我不是已经这样做,毕竟 result 不是引用,并且 usize
具有 Copy
特性),然后“删除引用”到 some_x
(是否会使用 drop(some_x);
,以便我可以修改 option_x
?此处提供了一个版本,但仍然不起作用:
fn get_x(&mut self) -> Option<usize> {
match self.option_x {
Some(ref mut some_x) => {
let result = some_x.get();
if some_x.times_accessed == self.max_access {
drop(some_x);
self.option_x = None;
}
Some(result)
}
None => {
println!("option_x is not initialized! try calling Y::init_x");
None
}
}
}
应该怎么办?
最佳答案
如错误消息所述,您在尝试替换 self.option_x
时引用其中的内容:
Some(ref mut some_x) => {
let result = some_x.get();
if some_x.times_accessed == self.max_access {
self.option_x = None; // <---------
}
Some(result)
}
访问 some_x
的突出显示点之后的任何代码都将获得无效值。这就是程序崩溃、暴露安全漏洞等的原因。
在 Rust 的潜在未来,理解非词法生命周期 的编译器可能会意识到您不使用该值,因此代码在当前状态下是可以的。在那之前,您可以从 Option
中取出整个值,如果不满足您的条件,则将其放回去:
match self.option_x.take() {
Some(mut some_x) => {
let result = some_x.get();
if some_x.times_accessed != self.max_access {
self.option_x = Some(some_x);
}
Some(result)
}
另见:
关于rust - 从子结构中获取值,然后修改子结构 : a borrow checker puzzle?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47623432/