盒子与标签:所有权入门
原理
所有权系统是 Rust 替代 GC 的核心机制,基于三个编译期规则实现静态内存管理:
栈上的值按位复制(memcpy)成本低;堆上的值通过指针访问,赋值时仅拷贝指针(Move),不深拷贝堆数据。编译器在函数退出点自动插入 drop 调用释放堆内存。
Copy trait 标记按位复制安全(stack-only 类型)。非 Copy 类型在赋值后原变量被编译器视为”未初始化”,产生 use-after-move 编译错误。这是通过 MIR(Mid-level IR)阶段的 move-checker 实现的 non-lexical lifetime 分析。
根本原因:避免 double-free。两个变量拥有同一块堆内存的所有权,作用域结束时均执行 drop → 两次 free → 未定义行为。
语法
Move 语义
let s1 = String::from("hello");
let s2 = s1; // s1 所有权转移给 s2
// println!("{}", s1); // 编译错误:use of moved valueCopy 类型(自动复制)
let x = 5;
let y = x; // x 仍然有效(i32 是 Copy)
println!("{} {}", x, y);实现 Copy 的基本类型:
| 类型 |
|---|
i8, i16, i32, i64, i128, isize |
u8, u16, u32, u64, u128, usize |
f32, f64 |
bool, char |
&T(不可变引用) |
(T1, T2, ...) 当所有字段都是 Copy |
Clone — 显式深拷贝
let s1 = String::from("hello");
let s2 = s1.clone(); // 堆数据深拷贝,s1 仍有效函数调用中的所有权
fn consume(s: String) { } // 接收所有权
fn main() {
let s = String::from("hi");
consume(s);
// println!("{}", s); // 编译错误:s 已移动
}fn give_back(s: String) -> String { s } // 归还所有权
let s = give_back(String::from("hi")); // 用遮蔽接收三条核心规则
- 每个值有且仅有一个所有者
- 所有者离开作用域时,值被
drop - 赋值/传参时:Copy 类型自动复制,非 Copy 类型产生 move
元组与 Copy
let t1 = (1, 2, 3); // 全 Copy → 元组可 Copy
let t2 = (1, String::from("h")); // 含非 Copy → 元组不可 Copy实践
力扣问题
力扣: 力扣简单模拟题 — 涉及值传递与所有权
fn main() {
let mut k: i64 = read_one();
let mut day = 1;
let mut sum = 0;
while k > 0 {
for _ in 0..day {
sum += day;
k -= 1;
if k == 0 { break; }
}
day += 1;
}
println!("{}", sum);
}AI 自检
String赋值时为何是 move 而非 copy?从内存布局解释(16或24字节栈数据 vs 堆数据)。- 若元组
(i32, String)不是 Copy,能否通过clone变通?clone 的代价是什么?