所有权(Ownership)是 Rust 最独特的特性,它让 Rust 无需垃圾回收器即可保证内存安全。所有权的三条规则:
1. Rust 中的每个值都有一个**所有者**变量 2. 同一时间只能有一个所有者 3. 当所有者离开作用域,值被自动释放
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 的所有权转移给 s2 // println!("{}", s1); // 编译错误:s1 已被移动(moved) println!("{}", s2); // 正常:s2 是所有者 }
这称为移动(Move)。移动后原变量失效,避免了双重释放。
标量类型实现了 Copy trait,赋值时是拷贝而非移动:
fn main() { let x = 5; let y = x; // x 仍然是有效的拷贝 println!("x={}, y={}", x, y); // 都能访问 // 实现 Copy 的类型: // - 所有整数类型 // - 浮点类型 // - 布尔类型 // - 字符类型 // - 元组(仅包含 Copy 类型时) }
传递变量给函数也会转移所有权:
fn take_ownership(s: String) { println!("我拥有了: {}", s); } // s 在此释放 fn main() { let s = String::from("hello"); take_ownership(s); // println!("{}", s); // 编译错误:所有权已转移 }
fn give_ownership() -> String { let s = String::from("world"); s // 返回所有权给调用者 } fn main() { let s = give_ownership(); println!("{}", s); // 正常:s 现在拥有所有权 }
如果确实需要复制堆上的数据,用 clone():
fn main() { let s1 = String::from("hello"); let s2 = s1.clone(); // 深拷贝堆数据 println!("s1 = {}, s2 = {}", s1, s2); // 都能访问 }
注意:clone() 是显式的,意味着开发者意识到这是昂贵的操作。
栈(Stack):后进先出,快速。存储大小固定的数据。
堆(Heap):慢速,大小未知或动态变化的数据。分配时返回指针。
fn main() { // i32 大小固定(4字节),在栈上 let x: i32 = 42; // String 大小可变,数据在堆上,指针在栈上 let s: String = String::from("hello"); // s 本身在栈上(指针+长度+容量) // "hello" 数据在堆上 }
Copy 类型赋值是拷贝,堆上的类型默认是移动clone() 显式进行深拷贝