所有权是什么
本教程共 78 篇 · 第 20 篇 · 更新于 2026-08-08 · 约 9 分钟阅读
本节目标:理解 Rust 内存管理的核心机制——所有权,记住三条铁律,并明白它如何在不靠垃圾回收的前提下保证内存安全。
从这一章起,我们进入 Rust 最独特、也最关键的部分:所有权(Ownership)。前面讲的变量、函数、循环,别的语言也有类似物;但所有权是 Rust 独有的”杀手锏”。它决定了内存什么时候分配、什么时候收回,而且是编译期就定好的。
别怕,把它拆开慢慢看,其实逻辑很生活化。
20-1 先想一个问题:内存谁管
程序跑起来要占用内存。一个值在内存里,总得有人负责”不用了就释放掉”,否则内存越占越多(泄漏),或者被释放了还在用(崩溃/安全漏洞)。
业界通常两招:
- 垃圾回收(GC):运行时有个管理员定期清扫。安全但拖慢程序,且回收时会卡顿。
- 手工管理:程序员自己 malloc/free。快但极易出错,C/C++ 大量 bug 源于此。
Rust 走第三条路:编译器在编译时,按一套规则追踪”每块内存归谁管”,管它的人离开作用域,内存自动释放。既没 GC 开销,又不用你手工 free,还几乎不出内存 bug。这套规则就叫所有权。
20-2 栈和堆:一句话区分
要懂所有权,得先知道值存在哪。内存分两块:
- 栈(stack):整齐、快。像一叠盘子,后进先出。大小固定、编译期已知的值放这(比如整数、bool、固定长度数组)。
- 堆(heap):灵活、稍慢。大小运行时才确定、可能变大的值放这(比如字符串内容、动态集合)。往堆里放东西,得先问系统”借一块”,拿到一个地址(指针)放栈上指过去。
所有权最操心的是堆上的数据——因为它大小不定、生命周期复杂。栈上的数据离开作用域自动弹出,不用操心;堆上的得有人负责还回去。
Note你不用精通内存管理细节,只要记住:编译期大小已知的值(整数、定长数组等)走栈;运行时大小才定的(字符串、Vec)走堆,需要所有权来管”谁负责释放”。
20-3 所有权的三条铁律
Rust 的所有权规则,说穿了就三条,请刻进脑子:
- ** Rust 中每个值都有一个被称为”所有者”(owner)的变量。**
- 同一时刻,一个值只能有一个所有者。
- 当所有者离开作用域(scope),这个值会被自动丢弃(drop),内存释放。
这三条是所有后续概念(移动、借用、切片)的总纲。下面逐一用例子感受。
20-4 作用域决定生死
作用域就是一对花括号 {} 包起来的范围。变量在作用域内有效,出了作用域就”死”:
fn main() {
{ // s 还没出生
let s = String::from("hello"); // s 出生,进入作用域
// 用 s 干点啥
} // 这里花括号结束,s 离开作用域 -> 内存被释放
}
String::from("hello") 在堆上分配了存 “hello” 的空间,栈上 s 指向它。当程序走出最内层花括号,s 失效,Rust 自动调用一个叫 drop 的动作,把堆内存还回系统。你一行 free 都没写。
Warning新手别担心”我忘了释放怎么办”。在 Rust 里,释放是编译器强制塞进去的,不是靠你记性。只要值的所有者离开作用域,drop 必发生。这正是它比 C 安全的地方。
20-5 为什么”只有一个所有者”
如果一块堆内存同时被两个变量当成”自己的”,那其中一个离开作用域时释放了它,另一个还以为自己合法持有——这就成了”悬垂指针”,用的时候崩溃。所以 Rust 规定:同一时刻只能有一个所有者。这就从根本上杜绝了”重复释放”和”释放后使用”。
那如果我就是想”把值交给另一个变量”呢?这就引出下一章的”移动(Move)“:交给别人的时候,原来的所有者主动放弃所有权,而不是两人共有。
20-6 哪些类型受所有权约束最明显
- 堆类型:
String、各种Vec、以及后面讲的结构体/枚举里含堆数据的,所有权规则最严格,赋值会触发”移动”。 - 栈类型(实现了 Copy 的类型):整数、浮点、bool、char、以及全由这些组成的元组/固定数组,赋值时会”复制一份”,不触发移动。这类叫 Copy 类型,稍后细讲。
简单说:小的、确定的走 Copy;大的、堆上的走所有权。理解这点,你才看懂为什么 let x = 5; let y = x; 没问题,而 let s = String::from("hi"); let t = s; 会”移动”。
20-7 一个类比帮你记
把堆上的值想成一把租来的钥匙(和对应的储物柜)。所有权就是”谁有权用这把钥匙、并负责归还”。规则:一把钥匙同一时间只在一人手里(唯一所有者);人走了(离开作用域)必须把钥匙还回去(drop)。你想把柜子交给朋友,得把钥匙亲手递过去、自己不再持有(移动)。这样永远不会出现”两人都以为自己有钥匙、却没人还”或”还了两遍”的混乱。
Tip学所有权时,别死记语法,先建立”唯一所有者 + 离开作用域就释放”的心智模型。后面移动、借用都是这套模型的推论,模型稳了,细节自然顺。
20-8 与垃圾回收的对照
把所有权和垃圾回收对照一下,能更清楚它站在什么位置。GC 语言(Java、Go、Python)运行时定期扫内存、回收不用的,程序员几乎不用管,代价是运行时有开销、回收时会卡顿、且仍可能因引用环泄漏。C/C++ 手工管内存,快但极易出错。Rust 的所有权把”谁负责释放”在编译期定死,既没 GC 开销,也几乎不出内存 bug——代价是你要花时间学这套规则。
Tip如果你从 GC 语言转来,会觉得”每分配一块堆内存都要想所有权”很累。但习惯后,大部分时候值在函数间自然流动,编译器替你管释放,你反而比以前更轻松、更敢写高性能代码。
20-9 小结
所有权三条铁律:每个值有唯一所有者;同一时刻只有一个所有者;所有者离开作用域值被 drop。它是 Rust 无 GC 也能内存安全的根基,主要约束堆数据。下一章看”把值交给别人”时发生的移动(Move),以及为什么整数是例外(Copy)。