我仍然很难理解为什么需要
&mut self
来修改我的结构拥有的对象的内部状态。我明白为什么我必须至少使用&self
,因为我不想消耗self
,结束它的存在。我也理解为什么如果我正在修改我的结构的字段我必须使用&mut self
,但我没有。
我有以下结构和实现:
struct Writer {
obj: json::JsonValue
}
impl<'b> Writer {
fn from(obj: json::JsonValue) -> Self {
Self {
obj
}
}
fn put(&mut self, field_name: &str, value: bool) {
self.obj.insert(field_name, value);
// ^^^- not modifying this, but a field inside "obj"
}
fn release_ownership(self) -> json::JsonValue {
self.obj
}
}
用法:
writer.put(field_name, true);
使用
&self
而不是 &mut self
我会得到一个编译器错误:
`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable`
Rust 书 教我:
如果我们想更改调用该方法的实例作为方法的一部分,我们将使用 &mut self 作为第一个参数。
我看不出如何修改这里的结构。我清楚地修改了一个字段(这里
obj
)in the struct,但不是struct本身。
的定义中我可以看到&mut self
,我也不明白,因为它“只”通过object
改变JsonValue::Object::insert()
的contents。
Rust book 说:
注意整个实例必须是可变的; Rust 不允许我们仅将某些字段标记为可变的。
我可以理解这一点,如果我想修改字段值,但如果字段是指向其他被修改的结构的指针,我就不能理解。
我的直觉告诉我,我用
&mut
限定不是指对数据的直接引用,而是指沿着所有指针或最终引用的整个路径。如果是这样的话:为什么会这样?
JsonValue::insert()
已经强制对其内部对象进行可变访问。所以编译器知道,JsonValue
的实例被可变地借用用于插入并且不能再次借用,直到它被释放。
家庭作业:阅读本书并进行搜索。
访问链上的所有内容都必须声明为可变引用,以确保您无法获得对同一对象的两个可变引用。考虑一下:
struct ContainsMutable<'a>(&'a mut i8);
fn main() {
let mut a = 99;
let cm = ContainsMutable(&mut a);
let cmref1 = &cm;
let cmref2 = &cm;
// now if both references allowed mutable access to the pointee
// `a` we'd have a problem because this would be allowed
std::thread::scope(|s| {
s.spawn(|| {
*cmref1.0 = 55;
});
s.spawn(|| {
*cmref2.0 = 31;
});
});
}
所以我们永远不能允许对共享引用背后的东西进行可变访问(我们通过路径上某处的共享引用访问的东西),因为我们可以很容易地以这种方式创建对同一对象的可变引用。
但是,这似乎是多余的,因为 JsonValue::insert() 已经强制对其内部对象进行可变访问。所以编译器知道,JsonValue 的实例是为插入而可变借用的,并且不能再次借用,直到它被释放。
假设编译器可以在编译时预测函数何时被调用并不允许这样做,但它不能,或者借用检查是在运行时完成的,不是,借用检查是在编译时静态完成的。您可以使用
RefCell
、Mutex
或 RwLock
进行运行时借用检查。