blog.dopana

Back

Rust入门系列第五篇。所有权是 Rust 最具特色的理念,也是它在没有垃圾回收器的情况下依然内存安全的原因。

三条规则#

  1. Rust 中每个值都有一个所有者。
  2. 同一时间只能有一个所有者。
  3. 当所有者离开作用域,值即被释放。
fn main() {
    let s = String::from("hello");
    println!("{s}");
}   // s 离开作用域;内存被释放
rust

Move 语义#

把值赋给另一个变量会移动所有权——旧的绑定不能再使用:

let s1 = String::from("hello");
let s2 = s1;
// println!("{s1}");   // 错误:值已被移动
println!("{s2}");      // 可以
rust

字符串没有被复制;它的数据和所有权都移给了 s2。这正是 Rust 没有 use-after-free 漏洞的原因。

Copy 类型#

复制成本低的小类型会被复制而非移动。它们实现了 Copy trait:

let a = 5;
let b = a;      // a 仍可使用
rust

整数、浮点数、布尔和 char 都是 CopyStringVec 不是。

Clone#

要复制堆上分配的值,需要显式调用 .clone()

let s1 = String::from("hello");
let s2 = s1.clone();
println!("{s1} {s2}");   // 两者都有效
rust

clone 做深拷贝。显式调用让成本一目了然。

所有权与函数#

把值传给函数会移动它;返回它又会移回来:

fn take_and_return(s: String) -> String {
    s
}

fn main() {
    let s = String::from("hi");
    let s = take_and_return(s);   // 移入,再移出
}
rust

所有权与作用域#

当所有者的作用域结束时,值即被释放。基于作用域的清理意味着资源——不只是内存——都会被自动释放。

为什么重要#

所有权让编译器能够证明不存在 use-after-free、double-free 和悬垂指针——这些正是困扰 C 和 C++ 的 bug。你写普通代码,编译器强制执行安全。

结论#

所有权:每个值一个所有者,默认 move,Copy 类型复制,深拷贝用显式 clone。本系列下一篇:引用与切片。

参考资料#