rustlings move_semantics2:传递不可变引用为何无法运行?
Rustlings move_semantics2练习引用传递代码报错原因及修正
问题背景
正在通过rustlings练习Rust入门,在move_semantics2练习中,尝试通过传递引用的方式在不转移所有权的情况下用vec0初始化vec1,但编写的代码无法编译。
我的代码
// move_semantics2.rs // Make me compile without changing line 13 or moving line 10! // Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint. // I AM NOT DONE fn main() { let vec0 = Vec::new(); let mut vec1 = fill_vec(&vec0); // Do not change the following line! println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); vec1.push(88); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); } fn fill_vec(vec: &Vec<i32>) -> &Vec<i32> { let mut vec = vec; vec.push(22); vec.push(44); vec.push(66); vec }
编译错误信息
⚠️ Compiling of exercises/move_semantics/move_semantics2.rs failed! Please try again. Here's the output: warning: variable does not need to be mutable --> exercises/move_semantics/move_semantics2.rs:8:9 | 8 | let mut vec1 = fill_vec(&vec0); | ----^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default error[E0596]: cannot borrow `*vec1` as mutable, as it is behind a `&` reference --> exercises/move_semantics/move_semantics2.rs:13:5 | 8 | let mut vec1 = fill_vec(&vec0); | -------- consider changing this binding's type to be: `&mut Vec<i32>` ... 13 | vec1.push(88); | ^^^^^^^^^^^^^ `vec1` is a `&` reference, so the data it refers to cannot be borrowed as mutable warning: variable does not need to be mutable --> exercises/move_semantics/move_semantics2.rs:19:9 | 19 | let mut vec = vec; | ----^^^ | | | help: remove this `mut` error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference --> exercises/move_semantics/move_semantics2.rs:21:5 | 19 | let mut vec = vec; | ------- consider changing this binding's type to be: `&mut Vec<i32>` 20 | 21 | vec.push(22); | ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference --> exercises/move_semantics/move_semantics2.rs:22:5 | 19 | let mut vec = vec; | ------- consider changing this binding's type to be: `&mut Vec<i32>` ... 22 | vec.push(44); | ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference --> exercises/move_semantics/move_semantics2.rs:23:5 | 19 | let mut vec = vec; | ------- consider changing this binding's type to be: `&mut Vec<i32>` ... 23 | vec.push(66); | ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 4 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0596`.
错误原因分析
所有报错都是E0596,核心原因是Rust的借用规则:
- 传递给
fill_vec的是不可变引用&Vec<i32>,Rust明确规定:不能通过不可变引用修改指向的内容。 - 函数里的
let mut vec = vec;只是让引用变量本身可变(允许它指向其他不可变引用),但引用指向的Vec依然是不可变的,因此调用vec.push()会触发错误。 - 主函数中
vec1是fill_vec返回的不可变引用,后续调用vec1.push(88)同样试图修改不可变引用指向的内容,违反借用规则。 - 两个
unused_mut警告也印证了这一点:声明mut的变量并没有被用来修改引用本身,完全多余。
修正方案(引用传递方式)
要通过引用实现修改,必须使用可变引用&mut Vec<i32>,同时要保证原变量是可变的:
- 将
vec0声明为mut,这样才能获取它的可变引用。 - 修改
fill_vec的参数和返回值类型为&mut Vec<i32>。 - 调用
fill_vec时传递&mut vec0。
修正后的代码
// move_semantics2.rs // Make me compile without changing line 13 or moving line 10! // Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint. fn main() { let mut vec0 = Vec::new(); // 修改为mut let mut vec1 = fill_vec(&mut vec0); // 传递可变引用 // Do not change the following line! println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); vec1.push(88); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); } fn fill_vec(vec: &mut Vec<i32>) -> &mut Vec<i32> { // 参数和返回值改为可变引用 vec.push(22); vec.push(44); vec.push(66); vec }
另一种符合练习要求的方案(克隆)
如果不想修改原vec0的内容,更简单的方式是克隆vec0,这样vec1拥有独立的所有权,不会影响vec0:
// move_semantics2.rs // Make me compile without changing line 13 or moving line 10! // Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint. fn main() { let vec0 = Vec::new(); let mut vec1 = fill_vec(vec0.clone()); // 克隆vec0 // Do not change the following line! println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); vec1.push(88); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); } fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> { // 接收所有权,修改后返回 vec.push(22); vec.push(44); vec.push(66); vec }
说明
- 可变引用方案中,vec0和vec1指向同一个Vec,所以修改vec1会同时改变vec0的内容,println输出时vec0的长度为3,内容是
[22,44,66]。 - 克隆方案中,vec0保持空,vec1是独立的Vec,两者互不影响,符合不修改原vec0的预期。
内容的提问来源于stack exchange,提问作者Cihaan
相关产品推荐
相关产品推荐

