Skip to content
On this page

Move语义2: exercises/move_semantics/move_semantics2.rs

题目

rust
// move_semantics2.rs
//
// Expected output:
// vec0 has length 3, with contents `[22, 44, 66]`
// vec1 has length 4, with contents `[22, 44, 66, 88]`
//
// 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);

    println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {}, with contents `{:?}`", "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
}

预期的返回:

txt
vec0 has length 3, with contents `[22, 44, 66]`
vec1 has length 4, with contents `[22, 44, 66, 88]`

题目解析

编译器提供的信息如下:

txt
⚠️  Compiling of exercises/move_semantics/move_semantics2.rs failed! Please try again. Here's the output:
error[E0382]: borrow of moved value: `vec0`
  --> exercises/move_semantics/move_semantics2.rs:17:65
   |
13 |     let vec0 = Vec::new();
   |         ---- move occurs because `vec0` has type `Vec<i32>`, which does not implement the `Copy` trait
14 |
15 |     let mut vec1 = fill_vec(vec0);
   |                             ---- value moved here
16 |
17 |     println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);
   |                                                                 ^^^^^^^^^^ value borrowed here after move
   |
note: consider changing this parameter type in function `fill_vec` to borrow instead if owning the value isn't necessary
  --> exercises/move_semantics/move_semantics2.rs:24:18
   |
24 | fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
   |    --------      ^^^^^^^^ this parameter takes ownership of the value
   |    |
   |    in this function
help: consider cloning the value if the performance cost is acceptable
   |
15 |     let mut vec1 = fill_vec(vec0.clone());
   |                                 ++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.

我们能读出的信息如下:

  • 借用了已经Move的值vec0
  • 由于vec0的类型是Vec<i32>类型,没有实现Copy trait,所以在let mut vec1 = fill_vec(vec0);处所有权转移。
  • 在所有权转移后,又在println里面读取了vec0导致失败。

Rust提供了集中方式来解决这个问题:

  • 第一种:您可以克隆一个vec0的数据,也就是创建一个副本,传递给fill_vec
rust
fn main() {
    let vec0 = Vec::new();

    let mut vec1 = fill_vec(vec0); 
    let mut vec1 = fill_vec(vec0.clone()); 

    println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {}, with contents `{:?}`", "vec1", vec1.len(), vec1);
}
  • 第二种:让fill_vec参数传递借用而不是传递带有所有权的形式,然后使用clone方法复制
rust
fn main() {
    let vec0 = Vec::new();

    let mut vec1 = fill_vec(vec0); 
    let mut vec1 = fill_vec(&vec0); 

    println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88);

    println!("{} has length {}, with contents `{:?}`", "vec1", vec1.len(), vec1);
}

fn fill_vec(vec: Vec<i32>) -> Vec<i32> { 
    let mut vec = vec; 
fn fill_vec(vec: &Vec<i32>) -> Vec<i32> { 
    let mut vec = vec.clone(); 

    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec
}
  • 第三种:让fill_vec参数使用可变借用类型,然后就可以直接进行修改它,然后不返回任何内容。但是这样也意味着,我们在fill_vec函数中对vec0进行了修改,vec1变得有些多余了。
rust
fn main() {
    let vec0 = Vec::new(); 
    let mut vec0 = Vec::new(); 

    let mut vec1 = fill_vec(vec0); 
    fill_vec(&mut vec0); 

    println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);

    vec1.push(88); 
    vec0.push(88); 

    println!("{} has length {}, with contents `{:?}`", "vec1", vec1.len(), vec1); 
    println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0); 
}

fn fill_vec(vec: Vec<i32>) -> Vec<i32> { 
fn fill_vec(vec: &mut Vec<i32>) {  
    let mut vec = vec;

    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec 
}

参考资料

Powered by VitePress