变量的赋值有两种语义,move和copy,C++和Rust作为系统级的编程语言,都实现了这两种语义,不过在表现形式上稍有不同。这里通过这两种语言的对比简单总结下C++和Rust中move和copy的不同,以及他们对函数签名函数传参的影响,希望能对大家理解move和copy有所帮助。
一、rust中的move和copy
在rust中,栈上的值的赋值操作默认是copy语义(实现了Copy trait):
let x = 5;
let y = x;
println!("x {} y {}", x, y);
上面的代码中,y是x的一个copy,copy之后,x和y都可以访问,上面的代码输出x 5 y 5
。较为复杂的堆上的对象,赋值操作默认是move语义:
如上面的代码,nums1通过赋值操作move给了nums2,转移了对这个值的ownership,这样nums1就不可以再访问了,上面第3行代码会报borrow of moved value: 'nums1'
的编译错误。修复上面编译报错有两种方法,一种是显示的clone:
let nums1 = vec![1, 2, 3];
let nums2 = nums1.clone();
println!("nums1 {:?} nums2 {:?}", nums1, nums2);
另外一种是borrow:
let nums1 = vec![1, 2, 3];
let nums2 = &nums1;
println!("nums1 {:?} nums2 {:?}", nums1, nums2);
上面这两种方法都会输出nums1 [1, 2, 3] nums2 [1, 2, 3]
。第一种方法nums1.clone()显示的把nums1复制了一份,这样并不影响nums1的ownership,复制完成之后,两个值是相互独立的;第二种方法&nums1是对nums1的一个引用,从语义上来说是对nums1这个值的借用。另外,rust在编译期检查了引用不能超过值的lifetime,保证引用的有效性,不会存在值已经释放而引用还在(dangling reference)的场景;同时