所有权是管理资源的一种方式,它确保了资源仅被正确的所有者所管理。
所有权机制不是 Rust 特有的,而是一种编程思想。它主要用来解决资源释放的问题。
在 C 语言中,所有权被凝练成一句话:谁创建谁析构,谁申请谁释放。
在 C++ 中,所有权是由移动语义和 RAII 构成的。
而 Rust 中的所有权是由编译器强制执行的。编译器在编译器分析资源的所有权,从而强制要求同一份资源在任一时刻只能有一个所有者。
将 C 和 Rust 进行对比,很容易发现:
C 是围绕拷贝语义构建的,Rust 是围绕移动语义构建的。
C 的拷贝语义发生在出现等号时。Rust 的移动语义发生在变量进入新作用域时。
由于 Rust 的移动语义发生在变量进入新作用域时,因此在 for 循环中也会导致转移所有权:
|
移动语义是 Rust 的基石。在 C 语言中,任何值都是可以被拷贝的,但在 Rust 中,任何值都是可以被移动的。
移动语义
移动语义代表了资源所有权的转移。
从实现上来看,移动语义是由 memmove 实现的。Rust 通过 memmove 将变量拷贝给新变量,然后使用 memset(如果是指针) 将旧变量作废,从而实现了所有权的转移。
资源销毁
Rust 资源自动销毁通过 Drop trait 实现。若变量实现了 Drop trait,则在退出作用域时自动执行 drop 函数。若结构体为 POD 类型,则无需实现 Drop。若结构体中含有实现了 Drop trait 的字段,则编译器会自动为当前结构体实现 Drop trait。
引用和指针的区别
Rust 的引用扮演着指针的作用。但是和指针略有不同:
可变引用使用移动语义。同一时刻只能存在一个。
不可变已用使用拷贝语义。可以存在多个。
可变引用和不可变引用是互斥的。
从另一方面,可以简单地将引用理解为读写锁,其中可变引用是写锁,不可变引用是读锁。写时不能获得读写锁,读时不能获得写锁。
Copy 语义
如果实现了 Copy traits,那类型就具备了拷贝语义。当类型存在拷贝语义时,变量的使用默认采用拷贝语义而不是移动语义。
不管是执行拷贝语义还是移动语义,Rust 都是通过浅克隆实现所有权的转义的(即 memmove )。两者的唯一区别只是前者不会导致旧值失效,后者会导致旧值失效。如果希望执行深拷贝,需要自己实现 Clone trait。 任何对移动语义带来性能优势的期望都是不显示的。移动语义是所有权的一部分,而所有权是用来解决多线程问题的。 |
闭包
默认情况下,变量为移动语义,闭包执行以下操作:
闭包没有修改变量。传入的变量为 &T。
闭包修改了变量。传入的变量为 &mut T。
使用 move。变量执行 move 语义。闭包只能执行一次。
如果变量实现了 Copy 语义,第三种情况变量执行拷贝语义而不是移动语义。闭包能执行多次。