用字符串案例解释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);
}