我正在读《铁锈》一书,我遇到了这个例子:
fn main() {
let a = [1, 2, 3, 4, 5];
let index = 10;
let element = a[index];
println!("The value of element is: {}", element);
}
书中说运行cargo run
后。。。
编译没有产生任何错误,但程序导致运行时错误,没有成功退出。
我不明白。我看到编译错误,即使通过cargo build
或rustc src/main.rs
进行编译,我也会看到错误。
在这个例子中它们是什么意思?为什么这不是编译错误,而是运行时错误?
编译器现在比以前更智能了,所以它会产生编译错误。
您需要更改代码,使其不太容易为编译器验证。例如:
fn main() {
let a = [1, 2, 3, 4, 5];
let index = a.len() + 1;
let element = a[index];
println!("The value of element is: {}", element);
}
上面的代码在当前版本(1.60(编译并恐慌。
此外,编译器通常只能证明数组([T; N]
(的边界访问,而不能证明切片和Vec
的边界访问。
Rust在书中得到了更聪明的持续评估。有一个打开的拉取请求,将本章更新为以下内容:
如果您试图访问数组中超过数组末尾的元素,会发生什么?如果您将示例更改为以下代码,它将不会编译:
fn main() {
let a = [1, 2, 3, 4, 5];
let index = 10;
let element = a[index];
println!("The value of element is: {}", element);
}
使用
cargo build
构建此代码会产生以下结果:
$ cargo run
Compiling arrays v0.1.0 (file:///projects/arrays)
error: this operation will panic at runtime
--> src/main.rs:5:19
|
5 | let element = a[index];
| ^^^^^^^^ index out of bounds: the len is 5 but the index is 10
|
= note: `#[deny(unconditional_panic)]` on by default
error: aborting due to previous error
error: could not compile `arrays`.
To learn more, run the command again with --verbose.
当编译器能够证明发生了无效的数组访问时,它将无法编译。然而,在某些情况下,编译不会产生任何错误,但程序本身会因运行时错误而失败,并且无法成功退出。
在运行时,当您尝试使用索引访问元素时,Rust将检查您指定的索引是否小于数组长度。如果索引大于或等于数组长度,Rust将死机。
这是Rust安全原则的第一个应用实例。在许多低级语言中,这种检查是不进行的,当您提供了不正确的索引时,可能会访问无效的内存。Rust通过不允许程序编译来保护您免受这种错误的影响,或者如果在编译时无法识别错误,它可能会在运行时死机,这将立即退出程序,而不是允许发生无效的内存访问。第9章详细讨论了Rust的错误处理。