07.所有权常见问题
引用和所有权
在 Rust 中,函数结束时:
- 所有在函数内部创建的变量(包括引用)都会被释放,引用(
&T或&mut T)都不能逃离函数作用域,因为它们只是对局部变量的借用。 - 但函数内部变量持有数据的所有权(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不能被可变借用。