You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>,同时要保证原变量是可变的:

  1. 将vec0声明为mut,这样才能获取它的可变引用。
  2. 修改fill_vec的参数和返回值类型为&mut Vec<i32>。
  3. 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:30:51