带有字符串字段的结构struct:
如果一个类型的所有组件都实现了Copy,那么它就可以实现Copy(copy类似语言自身的原型模式概念);
在下面这些列表中,我们关注的是Movie结构,它由一个没有实现Copy的String字段组成(原因见这里),因此,Movie不能实现Copy。
#[derive(Debug)] struct Movie { title: String, } fn main() { let movie = Movie { title: String::from("Rust") }; do_something(movie); } fn do_something(movie: Movie) { println!("Movie: {:?}!", movie); }
|
到目前为止看起来不错,不是吗?程序编译完毕(忽略了未使用字段的警告),我们都很高兴。输出:
Movie: Movie { title: "Rust" }!
|
但在加入println!后:
#[derive(Debug)] struct Movie { title: String, } fn main() { let movie = Movie { title: String::from("Rust") }; do_something(movie); println!("Movie: {:?}", movie); } fn do_something(movie: Movie) { println!("Movie: {:?}!", movie); }
|
编译器抱怨说我们试图借用一个已经移到do_something的值Movie。
编译器报错:
error[E0382]: borrow of moved value: `movie` --> src/main.rs:10:29
|
我们可以借用Movie而不是移动它。(Movie中有String字段,String不是值复制,也就是值无法移动的)
#[derive(Debug)] struct Movie { title: String, } fn main() { let movie = Movie { title: String::from("Rust") }; do_something(&movie); println!("Movie: {:?}", movie); } fn do_something(movie: &Movie) { println!("Movie: {:?}!", movie); }
|
输出:
Movie: Movie { title: "Rust" }! Movie: Movie { title: "Rust" }
|
或者我们可以为do_something克隆movie。这需要Movie实现Clone。
#[derive(Debug, Clone)] struct Movie { title: String, } fn main() { let movie = Movie { title: String::from("Rust") }; do_something(movie.clone()); println!("Movie: {:?}", movie); } fn do_something(movie: Movie) { println!("Movie: {:?}!", movie); }
|
或者,如果你的程序允许的话,我们可以在不克隆的情况下把两个代码行调换一下顺序。在这里,把movie借给println!,然后把movie移到do_something。
#[derive(Debug)] struct Movie { title: String, } fn main() { let movie = Movie { title: String::from("Rust") }; println!("Movie: {:?}", movie); do_something(movie); } fn do_something(movie: Movie) { println!("Movie: {:?}!", movie); }
|
Struct 包含u8 字段
如前所述,如果一个类型的所有组件都实现了Copy,它就可以实现Copy。
在下面列表中,我们关注的是由一个u8字段组成的Book结构,它实现了Copy特性。因此,Movie应该可以实现Copy的。
#[derive(Debug)] struct Book { id: u8, } fn main() { let book = Book { id: 1 }; do_something(book); } fn do_something(book: Book) { println!("Book: {:?}!", book); }
|
直到我们在do_something下面添加一个println!语句。发生了什么?
因为book没有实现Copy特性(或者还没有实现),Rust将book移动到do_something中。但是......因为book被移动了,println! 不能再使用这个值。
#[derive(Debug)] struct Book { id: u8, } fn main() { let book = Book { id: 1 }; do_something(book); println!("Book: {:?}", book); } fn do_something(book: Book) { println!("Book: {:?}!", book); }
|
报错:
error[E0382]: borrow of moved value: `book` --> src/main.rs:8:28
|
一种方法是通过派生Copy为Book实现Copy特性:
#[derive(Debug, Copy)] struct Book { id: u8, } fn main() { let book = Book { id: 1 }; do_something(book); println!("Book: {:?}", book); } fn do_something(book: Book) { println!("Book: {:?}!", book); }
|
还是报错:
error[E0277]: the trait bound `Book: Clone` is not satisfied --> src/main.rs:1:17
|
但是......我们仍然得到一个错误--triay绑定的Book。克隆没有得到满足。
如果我们去看文档,它说所有属于Copy的东西都必须同时实现Clone,因为Clone是一个超级属性。
因此,让我们在现有的Copy特质之上为Book实现Clone特质。
#[derive(Debug, Copy, Clone)] struct Book { id: u8, } fn main() { let book = Book { id: 1 }; do_something(book); println!("Book: {:?}", book); } fn do_something(book: Book) { println!("Book: {:?}!", book); }
|
正常输出:
Book: Book { id: 1 }! Book: Book { id: 1 }
|
我们也可以重新设计我们的程序,让 do_something 借用Book:
#[derive(Debug)] struct Book { id: u8, } fn main() { let book = Book { id: 1 }; do_something(&book); println!("Book: {:?}", book); } fn do_something(book: &Book) { println!("Book: {:?}!", book); }
|