Rust报错cannot assign to value behind & reference问题解析
Rust 编译错误 E0594 问题解答
核心报错为:cannot assign to first.value, which is behind a & reference,以下针对三个疑问逐一说明:
疑问1:为什么let mut first =写法无法让编译器认可first的可变性,支持修改first.value
Rust的可变性规则分为两层,二者互不干扰:
- 第一层是变量绑定本身的可变性:由
let mut声明,代表这个变量存储的值可以被替换,比如你可以让一个引用类型的变量重新指向其他地址。 - 第二层是引用指向内容的访问权限:由引用类型决定,
&T是不可变共享引用,仅提供读权限;&mut T是可变独占引用,提供读写权限。
你写的let mut first = &all_my_data[0]中,let mut仅让first这个变量本身可以被重新赋值(比如写first = &all_my_data[1]是合法的),但first持有的是不可变引用&Data,无论变量本身是否可变,都不能通过不可变引用修改指向的内容,因此修改first.value会触发报错。只有将右侧改为&mut all_my_data[0]拿到可变引用,才具备修改内部字段的权限。
疑问2:这个异常表现是否是因为数据被包裹在Box中导致的特殊行为?
不是。Box<T>是堆分配的智能指针,实现了标准的Deref/DerefMut trait,会透明转发内部值的借用权限,行为和直接存储T完全一致,不会改变Rust的借用规则。你可以将代码中的Box移除,直接向Vec中 push Data实例,依然会触发完全相同的E0594错误。
疑问3:赋值语句右侧的mut和左侧的mut作用有什么差异?
两个位置的mut修饰目标完全不同,作用无关联:
- 等号左侧
let mut 变量名中的mut:修饰变量绑定本身,代表该变量可以被重新赋值,不改变变量持有值的访问权限。 - 等号右侧
&mut T中的mut:修饰引用的访问权限,代表这是可变独占引用,只有持有该类引用时,才能修改引用指向的内存数据。
可以通过以下代码快速理解二者差异:
let mut data = Data::new("test"); let mut other_data = Data::new("other"); // 变量本身不可变,但持有可变引用:可以改指向的内容,不能让变量重新指向 let a = &mut data; a.value = "new value".to_string(); // 合法 // a = &mut other_data; // 报错:a是不可变绑定,不能重新赋值 // 变量本身可变,但持有不可变引用:可以让变量重新指向,不能改指向的内容 let mut b = &data; b = &other_data; // 合法 // b.value = "new value".to_string(); // 报错:b持有的是不可变引用,无写权限 // 变量可变+持有可变引用:既可以重新指向,也可以修改指向的内容 let mut c = &mut data; c.value = "new value".to_string(); // 合法 c = &mut other_data; // 合法
可复现代码
#![allow(unused)] fn main() { let mut all_my_data = Vec::new(); all_my_data.push(Box::new( Data::new("Hello World!"), ), ); all_my_data.push(Box::new( Data::new("This is the end of the World!"), ), ); all_my_data.push(Box::new( Data::new("Goodbye!"), ), ); let mut first = &all_my_data[0]; // This errors out //let mut first = &mut all_my_data[0]; // This works first.value = String::from("Hello New World!"); println!("First: {:?}", first); let second = &all_my_data[1]; println!("Second: {:?}", second); let third = &all_my_data[2]; println!("Third: {:?}", third); } #[derive(Debug)] struct Data { value: String, } impl Data { pub fn new(value: &str) -> Data { Data { value: value.to_string() } } }
编译报错信息
error[E0594]: cannot assign to `first.value`, which is behind a `&` reference --> src/main.rs:20:5 | 18 | let mut first = &all_my_data[0]; // This errors out | --------------- help: consider changing this to be a mutable reference: `&mut all_my_data[0]` 19 | //let mut first = &mut all_my_data[0]; 20 | first.value = String::from("Hello New World!"); | ^^^^^^^^^^^ `first` is a `&` reference, so the data it refers to cannot be written For more information about this error, try `rustc --explain E0594`. error: could not compile `playground` due to previous error
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

