【Rust中级教程】1.9. 所有权(简单回顾):所有权的核心思想、如何实现`Copy` trait、值的删除(丢弃)、值删除的顺序

发布于:2025-02-16 ⋅ 阅读:(107) ⋅ 点赞:(0)

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

这篇文章只对所有权进行简单回顾,想要看完整的所有权系统阐述见 【Rust自学】4.2. 所有权规则、内存与分配
请添加图片描述

1.9.1. 所有权的核心思想

Rust内存模型的核心思想是所有值都只有一个所有者。也就是说只有一个位置(通常是作用域来) 负责释放每个值。

这种效果是通过借用检查器实现的,如果值移动了(赋值新变量、推到Vec上、置于堆内存上等),其所有者也变成新的位置了。

所有者实际上就是内存上的一个位置,数据所在的位置就是值的所有者。移动指的是数据从一个位置转移到另一个位置,新的位置就是数据的所有者。

但是有些类型不执行这种规则:如果值的类型实现了Copy trait,那么在重新赋值时不是移动而是复制。也就是把值复制一份放到新的位置。

1.9.2. 如何实现Copy trait

实现Copy trait的类型必须可以按位(bit)来复制值。

能实现Copy trait的类型自然不包括:

  • 含有non-copy类型的类型
  • 如果一个类型在其值被丢弃时,必须执行某些特殊的资源释放操作

为什么呢?
想象一下,如果Box<T>实现了Copy trait,进行赋值:box1 = box2,这时候这两个变量都认为自己在堆内存上有一块专属于自己的空间,所以当它们走出作用域时,它们都会尝试释放那块内存,导致双重释放(double free),其危害在 【Rust自学】4.2.5. 内存和分配 中已作介绍,可以点击链接查看,这里不做重复。

1.9.3. 值的删除(丢弃)

当值不再被需要时,其所有者会将其删除。

值的删除(或者叫丢弃)发生于值走出作用域时。类型会递归地将其所包含的值删除。比如说我们要删除一个复杂类型的变量,会导致需要删除很多值。

但Rust不会发生多次删除同一个值的情况(因为所有权设计)。变量若含有对其他值的引用(不拥有该值),当变量被删除时,其它的值不会被删除。

这样说可能难理解,那我们看一个简单的例子:

fn main() {  
    let x1 = 42;  
    let y1 = Box::new(x1);  
  
    {  
        let z = (x1, y1);  
    }  
      
    let x2 = x1;  
}
  • x1i32类型,y1Box<i32>类型,指向x1
  • 使用{}创建了一个新的作用域,在这个小作用域里创建了z
  • z是元组类型,其值是(x1, y1)x1i32类型,实现了Copy trait,所以x是把自己的值复制了一份给zy1Box<i32>,没有实现Copy trait,所以它不能复制值,而是把所有权转移给了z
  • 离开了小作用域之后又使用了一次x1x1此时还保持有效在于x是把自己的值复制了一份给z,自身仍然保持有效。
  • y1在给z赋值之后就失效了,因为它把所有权转移给了z

1.9.4. 值删除的顺序

  • 变量(包括函数的参数)按照相反的顺序进行删除。
    在上面的例子中,y1是先声明的,z是后声明的。所以在删除时会先删z再删y1

  • 嵌套的值按照源代码的顺序进行删除。
    在上面的例子中,z在被删除时会按照先删除x1,再删除y1的顺序

注意:Rust暂时不允许在单个值内进行自我引用