用字符串案例解释Rust所有权概念


String是一种不实现Copy复制trait的类型(String默认是值传递,不是引用传递,也不是值复制):

让我们用它创建一个Stringthen 调用do_something:

fn main() {
    let name = String::from("Rust");
    do_something(name);
}

fn do_something(name: String) {
    println!(
"Hello, {}!", name);
}

在第 4 行添加一个println!语句……

fn main() {
    let name = String::from("Rust");
    do_something(name);
    println!(
"{}", name);
}

fn do_something(name: String) {
    println!(
"Hello, {}!", name);
}

编译器:

error[E0382]: borrow of moved value: `name`
 --> src/main.rs:4:20

这是不合法的!
因为我们试图使用(借用,在println的情况下!)已经在第3行被移入do_something的值名。(String默认是值传递,不是引用传递)

你不能使用一个已经被移动过的值。
在 println!之前的name 已经被移到 do_something 中,并在函数结束时超出了作用域。


我们可以做的是将name克隆为name_clone,(原型模式
这样我们在第5行使用name,在第6行使用name_clone。请注意,克隆是有代价的。

fn main() {
    let name = String::from("Rust");
    let name_clone = name.clone();

    do_something(name);
    println!(
"{}", name_clone);
}

fn do_something(name: String) {
    println!(
"Name: {}!", name);
}

或者我们可以在第3行通过引用将名字传给do_something,并且仍然能够在第4行将它用于println!

fn main() {
    let name = String::from("Rust");
    do_something(&name);
    println!(
"{}", name);
}

fn do_something(name: &str) {
    println!(
"Hello, {}!", name);
}

或者,如果你的程序允许,我们可以简单地把代码行相互调换一下顺序。

在这里,我们先借用name,然后再把它移到do_something中。这个程序可以编译,因为在do_something行之后,主作用域中没有其他人会使用name。

fn main() {
    let name = String::from("Rust");
    println!(
"{}", name);
    do_something(name);
}

fn do_something(name: String) {
    println!(
"Hello, {}!", name);
}