为什么Rust会在运行时检查数组边界,何时(大多数)其他检查在编译时发生?

时间:2015-02-08 00:56:32

标签: arrays compiler-errors runtime-error rust language-design

阅读basic introduction

  

如果您尝试使用不在数组中的下标,则会出现错误:在运行时对数组访问进行边界检查。

为什么Rust在运行时检查数组边界,看起来大多数其他检查在编译时发生?

1 个答案:

答案 0 :(得分:17)

因为在一般情况下,在编译时检查索引是不可行的。关于任意变量的可能值的推理即使对于小程序也是困难的和不可能的。没人想要:

  1. 正式证明索引不能超出界限,
  2. 将该证明编码到类型系统中
  3. ... 每个切片/ Vec /等。访问,因为这是您在编译时执行边界检查所必须执行的操作。你基本上需要依赖打字。

    除了可能使类型检查不可判断(并且使程序更难以进行类型检查)之外,类型推断通常变得不可能(并且在最好的情况下更加受限制),类型变得更加复杂和冗长,以及复杂性语言显着增加。只有在非常简单的情况下,如果没有大量额外的程序员工作,那么这些指数只能被证明。

    此外,没有动力去除边界检查。生命周期通过几乎完全消除对垃圾收集的需求来减轻它们的重量 - 这是一个巨大的侵入性功能,具有不可预测的吞吐量,空间和延迟影响。另一方面,运行时边界检查是非侵入性的,具有很小且众所周知的开销,并且可以在性能关键部分中选择性地关闭,即使程序的其余部分大量使用它也是如此。

    请注意,编译器可以数组的越界访问进行一些简单的检查:

    let a = [1, 2];
    let element = a[100];
    
    error: index out of bounds: the len is 2 but the index is 100
     --> src/main.rs:3:19
      |
    3 |     let element = a[100];
      |                   ^^^^^^
      |
      = note: #[deny(const_err)] on by default
    

    然而,这是有限的,并且通过使索引值不是明显的"而容易避免。常数:

    let a = [1, 2];
    let idx = 100;
    let element = a[idx];