赋值
白鹤亮翅
在绝大多数主流语言中,变量赋值通常要么是浅拷贝引用,要么是复制数值。赋值之后,原变量和新变量都能安然无恙地读取:
s1 = "hello"
s2 = s1
print(s1, s2) # hello hello
即便在 Rust 中,针对实现了 Copy trait 的基本数据类型(如整数、浮点数),赋值也是直接复制栈数据,各自安好:
let x = 5;
let y = x;
println!("{x} {y}"); // 5 5
当场打脸
换成拥有堆内存资源的复合类型(如 String),照着老习惯写:
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("{} {}", s1, s2);
}
编译器当场拒绝运行:
error[E0382]: borrow of moved value: `s1`
见招拆招
Rust 中没有实现 Copy trait 的类型(如 String),s2 = s1 进行的是所有权转移(Move)操作。一旦所有权移交给 s2,原变量 s1 在编译期就被标记为未初始化,无法再次访问,以此从根源上杜绝双重释放(double free)。
如果想要让 s1 和 s2 均独立有效,必须显式调用 .clone() 深拷贝堆上数据:
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{} {}", s1, s2);
// hello hello
在现代 C++(C++11 及以后)中,也有对应这种所有权转移思想的机制:std::move()。