为何Rust中此数组越界错误未在编译时被检测到?
Rust数组越界编译检查差异的原因
先看你给出的代码:
struct Foo { arr: [u8; 5] } fn main() { let foo = Foo{ arr: [0; 5] }; let bar = &foo; println!("{}", bar.arr[100]); // 编译通过,运行时触发panic // println!("{}", foo.arr[100]); // 编译直接报错 }
两者的差异核心在于编译器对数组访问形式的静态分析逻辑不同:
直接访问
foo.arr[100]时,foo.arr是拥有所有权的固定大小数组[u8;5]。Rust编译器会在编译阶段直接对比数组长度(5)和索引值(100),发现索引超出范围后直接抛出编译错误——这是Rust针对固定大小数组的常量索引做的静态安全检查。通过引用访问
bar.arr[100]时,bar.arr实际上是&[u8;5](对固定大小数组的引用)。此时Rust会自动将&[u8;5]强制转换为切片&[u8],而切片的长度在编译阶段无法被编译器精准追踪(哪怕逻辑上是固定值,编译器的静态分析规则也不会去深入推断引用背后的具体数组大小)。因此这种索引操作的越界检查只能推迟到运行时执行,所以代码能通过编译,但运行时会触发panic。
简单总结:直接操作拥有所有权的固定数组,编译器可做静态越界检查;操作数组的引用时会退化为切片操作,仅能在运行时做越界检查。
内容的提问来源于stack exchange,提问作者Phillip
相关产品推荐
相关产品推荐

