为何看似违反Rust所有权语义的代码可正常编译运行?
问题复现代码
fn main() { let arr: [i32; 4] = [1, 2, 3, 4]; let arr1: [i32; 4] = arr; println!("{:p}", &arr[0]); // 打印得到相同地址 println!("{:p}", &arr1[0]); // 打印得到相同地址 fn take_index(a: [i32; 4]) { print!("{}", a[2]); } take_index(arr1); print!("{}", arr[0]); }
现象成因
这个现象完全符合Rust设计规则,不存在所有权模型失效的问题,核心原因有两点:
- 赋值阶段根本没有触发所有权移动:固定长度、元素为基础数值类型的数组
[i32;4]默认实现了Copytrait。按照Rust所有权规则,实现Copy的类型在赋值、作为函数参数传递时走值复制逻辑,不会发生所有权转移,原变量始终持有对应数据的所有权,后续访问arr完全合法,不会触发编译错误。 - 地址相同是编译器的只读内存去重优化:两个数组首元素地址一致和多所有者没有任何关系,只是rustc做的冗余内存消除处理。当前代码里两个数组存储的内容完全一致,且全程没有对任何一个数组的修改操作,编译器会直接省略无意义的内存复制步骤,让两个不可变变量指向同一块只读内存,减少不必要的内存开销。这个优化是绝对内存安全的:只要后续代码出现任意对其中一个数组的修改操作,比如加一行
arr[0] = 99;,编译器会立刻为两个变量分配独立的内存空间,再打印地址就会发现二者指向不同位置,绝不会出现多个写权限持有者操作同一块内存的情况。
内容的提问来源于stack exchange,提问作者Akash P.
相关产品推荐
相关产品推荐

