1.9 所有权简单回顾所有权的核心思想、如何实现 Copy trait、值的删除(丢弃)、值删除的顺序这篇文章只对所有权进行简单回顾。1.9.1. 所有权的核心思想Rust内存模型的核心思想是所有值都只有一个所有者。也就是说只有一个位置通常是作用域来 负责释放每个值。这种效果是通过借用检查器实现的如果值移动了赋值新变量、推到Vec上、置于堆内存上等其所有者也变成新的位置了。所有者实际上就是内存上的一个位置数据所在的位置就是值的所有者。移动指的是数据从一个位置转移到另一个位置新的位置就是数据的所有者。但是有些类型不执行这种规则如果值的类型实现了Copytrait那么在重新赋值时不是移动而是复制。也就是把值复制一份放到新的位置。1.9.2. 如何实现Copytrait实现Copytrait的类型必须可以按位(bit)来复制值。能实现Copytrait的类型自然不包括- 含有non-copy类型的类型- 如果一个类型在其值被丢弃时必须执行某些特殊的资源释放操作为什么呢想象一下如果BoxT实现了Copytrait进行赋值box1 box2这时候这两个变量都认为自己在堆内存上有一块专属于自己的空间所以当它们走出作用域时它们都会尝试释放那块内存导致双重释放(double free)其危害在 4.2. 所有权规则、内存与分配 中已作介绍可以点击链接查看这里不做重复。1.9.3. 值的删除(丢弃)当值不再被需要时其所有者会将其删除。值的删除或者叫丢弃发生于值走出作用域时。类型会递归地将其所包含的值删除。比如说我们要删除一个复杂类型的变量会导致需要删除很多值。但Rust不会发生多次删除同一个值的情况因为所有权设计。变量若含有对其他值的引用不拥有该值当变量被删除时其它的值不会被删除。这样说可能难理解那我们看一个简单的例子fn main() { let x1 42; let y1 Box::new(x1); { let z (x1, y1); } let x2 x1; }x1是i32类型y1是Boxi32类型它拥有堆上的一块分配里面存的是x1值的副本因为i32实现了CopyBox::new(x1)并不会借用x1使用{}创建了一个新的作用域在这个小作用域里创建了zz是元组类型其值是(x1, y1)x1是i32类型实现了Copytrait所以x1是把自己的值复制了一份给zy1是Boxi32没有实现Copytrait所以它不能复制值而是把所有权转移给了z离开了小作用域之后又使用了一次x1x1此时还保持有效因为x1是把自己的值复制了一份给z自身仍然保持有效。而y1在给z赋值之后就失效了因为它把所有权转移给了z1.9.4. 值删除的顺序变量包括函数的参数按照相反的顺序进行删除。嵌套的值按照源代码的顺序进行删除。在上面的例子中当离开内部作用域时会删除z它先删除第一个元素那个被复制的i32再删除第二个元素那个Box。因为y1的所有权已经移动进z之后不会再单独删除y1。注意Rust暂时不允许在单个值内进行自我引用
【Rust中级教程】1.9. 所有权(简单回顾):所有权的核心思想、如何实现`Copy` trait、值的删除(丢弃)、值删除的顺序
1.9 所有权简单回顾所有权的核心思想、如何实现 Copy trait、值的删除(丢弃)、值删除的顺序这篇文章只对所有权进行简单回顾。1.9.1. 所有权的核心思想Rust内存模型的核心思想是所有值都只有一个所有者。也就是说只有一个位置通常是作用域来 负责释放每个值。这种效果是通过借用检查器实现的如果值移动了赋值新变量、推到Vec上、置于堆内存上等其所有者也变成新的位置了。所有者实际上就是内存上的一个位置数据所在的位置就是值的所有者。移动指的是数据从一个位置转移到另一个位置新的位置就是数据的所有者。但是有些类型不执行这种规则如果值的类型实现了Copytrait那么在重新赋值时不是移动而是复制。也就是把值复制一份放到新的位置。1.9.2. 如何实现Copytrait实现Copytrait的类型必须可以按位(bit)来复制值。能实现Copytrait的类型自然不包括- 含有non-copy类型的类型- 如果一个类型在其值被丢弃时必须执行某些特殊的资源释放操作为什么呢想象一下如果BoxT实现了Copytrait进行赋值box1 box2这时候这两个变量都认为自己在堆内存上有一块专属于自己的空间所以当它们走出作用域时它们都会尝试释放那块内存导致双重释放(double free)其危害在 4.2. 所有权规则、内存与分配 中已作介绍可以点击链接查看这里不做重复。1.9.3. 值的删除(丢弃)当值不再被需要时其所有者会将其删除。值的删除或者叫丢弃发生于值走出作用域时。类型会递归地将其所包含的值删除。比如说我们要删除一个复杂类型的变量会导致需要删除很多值。但Rust不会发生多次删除同一个值的情况因为所有权设计。变量若含有对其他值的引用不拥有该值当变量被删除时其它的值不会被删除。这样说可能难理解那我们看一个简单的例子fn main() { let x1 42; let y1 Box::new(x1); { let z (x1, y1); } let x2 x1; }x1是i32类型y1是Boxi32类型它拥有堆上的一块分配里面存的是x1值的副本因为i32实现了CopyBox::new(x1)并不会借用x1使用{}创建了一个新的作用域在这个小作用域里创建了zz是元组类型其值是(x1, y1)x1是i32类型实现了Copytrait所以x1是把自己的值复制了一份给zy1是Boxi32没有实现Copytrait所以它不能复制值而是把所有权转移给了z离开了小作用域之后又使用了一次x1x1此时还保持有效因为x1是把自己的值复制了一份给z自身仍然保持有效。而y1在给z赋值之后就失效了因为它把所有权转移给了z1.9.4. 值删除的顺序变量包括函数的参数按照相反的顺序进行删除。嵌套的值按照源代码的顺序进行删除。在上面的例子中当离开内部作用域时会删除z它先删除第一个元素那个被复制的i32再删除第二个元素那个Box。因为y1的所有权已经移动进z之后不会再单独删除y1。注意Rust暂时不允许在单个值内进行自我引用