所有权

rust中所有权是对变量所指向内存的一种抽象。在内存的空间性加上时间性这个特性。内存的空间性是指它具有的唯一内存地址。但我们往往忽略了内存的时间性。体现了内存时间性最为明显的地方一个是局部变量所指向的内存,一个是堆上的内存。
局部变量所指向的内存随时被回收,堆上的内存永远不知道什么时候被回收。
rust通过所有权机制保证了,只要拥有所有权的变量在此时所指向的内存(资源)一定存在。
我们知道变量是什么时候获得内存,但什么时候释放它是一个问题?
rust通常通过作用域来决定什么时候释放资源。注意这里指的是资源,资源不只是内存。

作用域

作用域的声明为{}。
只要是{}所包裹的代码块都看作一个作用域。当一个作用域结束,rust会释放所有拥有所有权资源的变量。

  1. let mut x = String::from("hello world");
  2. {
  3. let mut y = x;
  4. y.push('!');
  5. println!("{:?}", y);
  6. }
  7. println!("{:?}", x);

在上面的代码中,第三行y获得了x的所有权,然后在第六行释放了所有权。所以当第7行再次获取x的时候,会报错。
注意:x此时还存在,只是编译器检查的时候,发现所有权已经转移,禁止访问了。

  1. {
  2. let mut x = String::from("hello world");
  3. x.push('!');
  4. println!("{:?}", x);
  5. }
  6. println!("{:?}", x);

上面的代码中,在第6行会发现x其实是未声明的。

drop

我们知道了变量会在作用域结束的时候释放资源,但怎么释放,其实是掌握在编写者的手中,在其他语言中,这个函数通常叫做析构函数,在rust中,我们使用drop这个trait来完成。
注:trait,rust中用来组织函数的语法。

  1. struct TestDrop;
  2. impl Drop for TestDrop {
  3. fn drop(&mut self) {
  4. println!("TestDrop drop!");
  5. }
  6. }
  7. println!("start!");
  8. {
  9. let _x = TestDrop {};
  10. }
  11. println!("end!");

运行上面代码,会出现下述情况。

  1. start!
  2. TestDrop drop!
  3. end!

紧接着上面的代码,我们看下rust如何drop一个复杂数据类型(自定义数据类型)。代码如下:

  1. struct TestDrop;
  2. impl Drop for TestDrop {
  3. fn drop(&mut self) {
  4. println!("TestDrop drop!");
  5. }
  6. }
  7. struct TestDropTwo {
  8. one: TestDrop,
  9. two: TestDrop,
  10. }
  11. impl Drop for TestDropTwo {
  12. fn drop(&mut self) {
  13. println!("TestDropTwo drop!");
  14. }
  15. }
  16. println!("start!");
  17. {
  18. let _x = TestDropTwo {
  19. one: TestDrop {},
  20. two: TestDrop {},
  21. };
  22. }
  23. println!("end!");
  24. }

上述代码会输出如下结果:

  1. start!
  2. TestDropTwo drop!
  3. TestDrop drop!
  4. TestDrop drop!
  5. end!

通过结果可知,拥有所有权的变量离开作用域后,会自动调用drop来回收资源。drop函数从最高级的抽象开始,逐步向下调用,直至资源回收干净。需要注意的是,实现了Copy这个trait的变量来离开作用域是不会触发drop。