Skip to content

07.所有权常见问题

引用和所有权

在 Rust 中,函数结束时:

  1. 所有在函数内部创建的变量(包括引用)都会被释放引用(&T&mut T)都不能逃离函数作用域,因为它们只是对局部变量的借用。
  2. 但函数内部变量持有数据的所有权(ownership)可以被转移,这样数据不会被释放,而是交给函数的调用者管理。
rust
fn main() {
    println!("引用和所有权");
    let value = return_a_string();
    println!("{value}");
}

fn return_a_string() -> String {
    let s = String::from("Hello World");
    s
}

输出:

引用和所有权
Hello World

但是,引用不能被传递,脱离函数作用域,以下代码将报错:

rust
fn main() {
    let &value = return_a_string();
    println!("{value}")
}

fn return_a_string() -> &String {
    let s = String::from("Hello World");
    &s
}

Copy 和所有权的转移

以下代码:

rust
let v = vec![1,2,3];
let n_ref = &v[0];
let n = *n_ref;

let v = vec![String::from("Hello World")];
let s_ref = &v[0];
// let s = *s_ref;  // ❌

int 类型在 rust 中默认实现了 copy ,因此,当尝试将 v 中的元素赋值给一个新的元素时,会默认将该元素复制一份给到新变量,不会对原有包括 v 的数据产生影响,因此可以正常执行 let n = *n_ref; ;但 String 类型默认没有实现 copy ,rust 认为如果实现了 String 的 copy ,将会产生较大开销,rust 默认避免这种行为,因此,当尝试将一个 String 数据赋值给新元素时,rust 不会复制新元素,而是尝试将所有权进行转移给新元素,但上述的变量是一个引用,即 s_ref ,而引用是不具备所有权的,因此无法将所有权移动给新变量 s ,从而发生错误。

正确的做法是创建一个克隆:

rust
let s = v[0].clone();

借用规则针对每个字段单独应用

以下代码:

rust
let mut name = (String::from("Tom"), String::from("Mike"));
let first = &name.0;
name.1.push_str("do");
println!("{first} {}", name.1);
  • 在创建了 name 第一个元素的不可变引用 first 后,name 的第一个元素失去写权限(直到 first 使用完成),但第二个元素仍具有写权限,不可变借用 name.0 不会影响 name.1 的修改权限。
  • name 的第一个元素(name.0)的不可变引用已经被创建时,整个 name 不能被可变借用