Appearance
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
}