Rust 所有权

17 Mar 2025 | 4 分钟阅读

理解所有权

所有权是 Rust 编程语言提供的独特功能,它保证了内存安全,而无需使用垃圾收集器或指针。

什么是所有权?

当一段代码块拥有一个资源时,它被称为所有权。代码块创建一个包含资源的 object。当控制到达块的末尾时,该 object 被销毁,并且资源被释放。

所有权的重要点

  • "所有者"可以根据可变性更改变量的所有权值。
  • 所有权可以转移到另一个变量。
  • 所有权只是 Rust 中的移动语义。
  • 所有权模型还保证了并行中的安全性。

所有权规则

  • 在 Rust 中,每个值都有一个与之关联的变量,这被称为它的所有者。
  • 一次只能有一个所有者。
  • 当所有者超出范围时,与其关联的值将被销毁。

所有权的例子

多个变量可以在 Rust 中相互交互。让我们看一个例子

将 x 的值分配给变量 y

在上面的例子中,x 绑定到值 10。然后,x 的值被分配给变量 y。在这种情况下,不会创建 x 的副本,而是将 x 的值移动到变量 y。因此,x 的所有权转移到变量 y,并且变量 x 被销毁。如果我们尝试重用变量 x,那么 Rust 会抛出一个错误。让我们通过一个例子来理解这一点。

以下是上述例子的输出


Rust Ownership

内存和分配

在 Rust 中,数据可以存储在堆栈或堆内存中。


Rust Ownership

堆栈内存: 在堆栈内存中,数据总是按顺序放置,并按相反的顺序删除。它遵循“后进先出”的原则,即最后插入的数据总是先被删除。堆栈内存是一种有组织的内存。它比堆内存更快,因为它访问内存的方式。如果在编译时不知道数据的大小,那么使用堆内存来存储内容。

堆内存: 堆内存是一种有组织的内存。操作系统在堆内存中找到一个空闲空间并返回一个指针。这个过程被称为“在堆上分配”。


Rust Ownership

此图显示堆栈包含指针,而堆包含内容。

让我们看一个简单的内存分配示例。

步骤 1

在程序的第一个语句中,向量 v1 绑定到值 1、2 和 3。向量由三部分组成,即指向存储在内存中的数据的指针、长度和向量的容量。这些部分存储在堆栈中,而数据存储在堆内存中,如下所示


Rust Ownership

步骤 2

在程序的第二个语句中,v1 向量被分配给向量 v2。指针、长度和容量被复制到堆栈中,但我们不会复制堆内存中的数据。让我们看一下内存表示


Rust Ownership

然而,这种类型的表示可能会造成问题。当 v1 和 v2 都超出范围时,它们都会尝试释放内存。这将导致双重释放内存,从而导致内存损坏。

步骤 3

Rust 避免了第 2 步的条件以确保内存安全。Rust 没有复制已分配的内存,而是认为 v1 向量不再有效。因此,它不需要释放 v1 的内存,因为 v1 超出了范围。


Rust Ownership

使用 Copy trait

Copy trait 是一个特殊的注解,它放置在堆栈上存储的类型(如整数)上。如果将 copy trait 用于这些类型,那么即使在赋值操作之后也可以进一步使用旧变量。

以下是某些是 copy 的类型

  • 所有整数类型,例如 u32。
  • 布尔类型,bool,值为 true 或 false。
  • 所有浮点类型,例如 f64。
  • 字符类型,char。

所有权和函数

当变量传递给函数时,所有权将移至已调用的函数的变量。传递值的语义等于将值分配给变量。

让我们通过一个例子来理解这一点

输出

javaTpoint
a
a

在上面的例子中,字符串 's' 绑定到值 "javaTpoint",并且 's' 变量的所有权通过 take_ownership() 函数传递给变量 'str'。'ch' 变量绑定一个值 'a',并且 'ch' 变量的所有权通过 moves_copy() 函数传递给变量 'c'。'ch' 变量也可以在之后使用,因为此变量的类型是 "copy" trait。

返回值和作用域

从函数返回值也会转移所有权。让我们看看这个:

输出

value of x is 100

在上面的例子中,gives_ownership() 函数返回 y 的值,即 100,并且 y 变量的所有权转移到 x 变量。


下一个主题Rust 引用和借用