您现在的位置是:首页 >技术杂谈 >RUST 每日一省:所有权网站首页技术杂谈

RUST 每日一省:所有权

许汶强 2023-06-03 12:00:03
简介RUST 每日一省:所有权

        所有权是是Rust语言中的基础设施。 Rust中的每个值都必定有一个唯一的所有者,所有者负责该值的释放和读写权限。

“所有权”代表着以下意义:

  • 每个值在Rust中都有一个变量来管理它, 这个变量就是这个值、 这块内存的所有者;
  • 每个值在一个时间点上只有一个所有者;
  • 当所有者离开自己的作用域时,它持有的值就会被释放掉。

值类型&引用类型   

        栈和堆都是代码在运行时可供使用的内存,但它们存储数据的方式不同,决定了编程语言中的值主要分为两类:值类型和引用类型。

        栈内存存储的数据大小在编译时已知且固定,数据的生命周期是短暂的, 会随着栈展开的过程而被自动清理。 值类型是指数据直接存储在栈中的数据类型 ,一些原生类型, 比如数值、 布尔值、 结构体等都是值类型。 因此对值类型的操作效率一般比较高, 使用完立即会被回收。

        而堆内存存储的数据大小在编译时未知或可能发生变化,也就是只有在程序运行时才能确定数据的大小。所以我们说他是动态的, 其分配和重新分配并不遵循某个固定的模式, 所以需要使用指针来对其进行跟踪。引用类型将数据存储在堆中, 而栈中只存放指向堆中数据的地址(指针) , 比如数组、 字符串等。 因此对引用类型的操作效率一般比较低, 使用完交给GC回收, 没有GC的语言则需要靠手工来回收。

值语义&引用语义

我们对这两种情况进行一个更精准的描述,值语义,引用语义;

        值语义是指按位复制后与原值无关,保证值的独立性。基本数据类型都是值语义。要修改具有值语义特性的变量,只能通过它本身来修改;修改了具有值语义特性的变量,并不会影响复制的值。

        引用语义是指数据存储在堆内存中,通过存储在栈内存的指针来管理堆内存的数据,并且禁止按位复制。因为按位复制只能复制栈上的指针,这样就会有两个栈上的指针指向堆上的同一数据容易造成堆上数据二次释放。

        按位复制就是指栈复制 , 也叫浅复制, 它只复制栈上的数据。 相对而言, 深复制就是对栈上和堆上的数据一起复制。

        所有权系统要做的正是跟踪代码正在使用的堆上数据,最大限度地减少堆上重复的数据,及时清理堆上不再使用的数据,确保垃圾数据不会耗尽内存空间等。
 

移动语义&复制语义

        在Rust中, 由Copy trait来区分值语义和引用语义。对于实现 Copy 的类型, 也就是复制语义类型。复制语义对应值语义,具有值语义特性的变量可以在栈上进行按位复制,以便于内存管理。比如整数、bool, 让它们在赋值的时候默认采用按位复制操作会让语言更简单。

        但是对于禁止实现Copy的类型,也就是移动语义类型,对应引用语义。在进行赋值操作时,如果对其执行按位复制, 就会出现重复释放同一块堆内存的问题, 所以在进行赋值时,需要把拥有的值转移给另外一个变量, 称为“所有权转移”。 赋值语句、 函数调用、 函数返回等, 都有可能导致所有权转移。Rust中所有权转移的重要特点是, 它是所有类型的默认语义。Rust中的变量绑定操作, 默认是move语义, 执行了新的变量绑定后, 原来的变量就不能再被使用! 一定要记住!

所有权

        Rust中每个值都有一个所有者, 更进一步说就是, Rust中分配的每块内存都有其所有者, 所有者负责该内存的释放和读写权限, 并且每时每个值只能有唯一的所有者。 这就是 Rust的所有权机制 。对于可以实现 Copy 的复制语义类型来说, 所有权并未改变。 对于复合类型来说, 是复制还是移动, 取决于其成员的类型。

        所有者除了可以释放和读写权限之外。其实还可以转移所有权,也可以出借所有权,这个下次再讨论。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。