所有权
写程序不可避免要管理内存,而内存管理是非常容易出错的,有的语言使用垃圾回收机制,有的靠开发者自己管理。垃圾回收会降低执行效率,开发者自己管理对开发要求很高。Rust突破限制,使用独有的所有权机制解决内存管理问题。
所有权与堆栈关系密切。栈和堆使用效率是有区别的,栈是有序的,所以使用起来更快。堆是随机存储的,跳跃存取肯定要比顺序存取慢。变量存入栈时必须知道大小,而堆可以不确定大小,分配一块足够大的内存区域即可。可是分配时需要寻找一块足够大的块,这就要花费些时间。
所有权有三个特点:
每个变量都有他的所有者
所有者同时只有一个
所有者出了作用域就会释放变量
以String为例,String大小是变化的,所以是在运行时分配的,并且需要申请堆内存,堆内存的申请是通过from方法,申请之后的释放往往是关键。有些语言通过gc控制,自动回收;有些没有gc的语言需要手动释放;rust则是通过在作用域结束自动调用drop方法来释放的。
Move:
下面的代码中x和y的值都是5,而且都存储在栈上,实际上是栈上有两个5,y=x的时候复制了一个到栈上,所以有两个,而不是同时指向一个。
对于复杂类型,也就是数据存储在堆中的类型,复制的只是栈上的内容,并不复制堆中的内容。
s1在栈中存储了指向堆的指针、字符串长度和可存储容量。赋值时,s2复制了s1的栈信息,指向与s1相同的堆内存,然后s1会失效。相当于将堆内存从s1移动到了s2,所以赋值操作称为移动。移动=浅拷贝+失效旧变量。
如果想要实现深拷贝,也就是堆数据也被拷贝,则使用clone方法即可。
标量类型,占用的内存大小是确定的,存储在栈中的,默认都是实现了clone特性的,深拷贝与浅拷贝是相同的。包含标量类型的tuple默认也实现了clone,如(i32, i32)实现了,(i32, String)没实现。
实现了drop特性的类型不能再实现clone。
对于函数的入参和返回参数都是和赋值操作类似的,也会有变量的move操作。
当堆中的变量离开作用域时,会调用drop,但是如果变量move了,失去了所有权就不会调drop了。
如果除了返回move参数外,想返回多个附加数据,那么一种方法是可以用tuple来传递。