上一篇我们说到,实现了copy trait的变量在作用域结束时,触发drop机制。
那为什么实现了copy trait不发触发drop?
copy trait在std::marker中被定义,对它的说明为:实现了此trait的类型按位复制即可轻易获得其值。这里vec作为举例来说明move/clone/copy的区别。
注:vec,一个动态数组,容器。
一个vec动态数组有三个要素:

  • len(长度)
  • capacity(容量)
  • data(指针)

len代表当前数组有多个元素,capacity代表当前数组的容量,data指向了这个空间容量的首地址。
动态数组最特殊的地方在于data/capacity都是会变化的,它能通过缩容和扩容的手段来获得合适的容量来保持复杂度。
它的数据逻辑如下图;

move

当我们通过运算符=将这个vec绑定在一个新变量上,代码如下:

  1. let x = vec![1, 2, 3];
  2. let y = x;//move

此时第二行这里发生的过程叫move;那这个过程是怎么样的?
当第二行执行时,我们说所有权发生了转移。在内存中的转换如图:

  • 按位复制
  • 转移所有权

当第二行执行时,原本data所指向的数据被禁止,连带着原先整个变量被禁止访问,此时x还存在内存中。
具体例子如下:

  1. let mut x = vec![1, 2, 3];
  2. println!("x:{:p}", &x);
  3. println!("x:{:?}", x);
  4. let y = x;
  5. println!("y:{:?}", y);
  6. println!("y:{:p}", &y);
  7. x = vec![4, 5, 6];
  8. println!("x:{:?}", x);
  9. println!("x:{:p}", &x);

此处,两次x的地址一致。

clone

clone trait的解释为:无法轻易按位复制便能获得的值。对于此种类型,我们必须手动实现clone trait。并且这个方法无法使用运算符重载。
vec的clone示意图如下:
clone进行了两次操作。

  • 按位复制
  • 在堆中生产了新的空间。
  • 改变了data的值。

    copy

    copy同样是手动的trati,只是它并没有需要实现的方法,它是一个标记的trait,这样的trait还有很多,我们后面会见到。
    那此时会有疑问,没有特定的方法,那么如何实现copy操作。
    copy/move在栈上的内容都是按位复制值。