为什么Rust编译器允许索引超出范围?

mhr*_*che 19 rust

有人可以解释为什么编译:

fn main() {
    let a = vec![1, 2, 3];
    println!("{:?}", a[4]);
}
Run Code Online (Sandbox Code Playgroud)

运行时,我得到:

线程''惊慌失措'索引越界:len是3但索引是4',../src/libclections/vec.rs:1132

Mat*_* M. 17

为了理解这个问题,你必须根据编译器看到的内容来考虑它.

通常情况下,编译器永远不会对表达式的进行推理,只会考虑其类型.从而:

  • a 是类型的 Vec<i32>
  • 4 是一个未知的整数类型
  • Vec<i32>实现下标,所以a[4]键入检查

有编译器推理值的方法并不为人所知,并且有各种方法可以获得它.

  • 你可以允许在编译时评估一些表达式(constexpr例如C++ )
  • 你可以将值编码为类型(C++非类型模板参数,使用Peano的数字)
  • 你可以使用依赖类型来弥补类型和值之间的差距

Rust目前还不支持这些中的任何一个,虽然对前者有兴趣,但在1.0之前肯定不会这样做.

因此,在运行时检查这些值,并Vec正确地执行正确的操作(此处失败).

  • llvm,rustc的优化编译器后端,然而当它开始优化代码时,它会看到这些抽象层.所以我们可以看到它在这种特殊情况下将其静态编译为失败的边界检查. (2认同)

mwh*_*ker 16

如果要访问Vec带索引检查的元素,可以将其Vec 用作切片,然后使用其get方法.例如,请考虑以下代码.

fn main() {
    let a = vec![1, 2, 3];
    println!("{:?}", a.get(2));
    println!("{:?}", a.get(4));
}
Run Code Online (Sandbox Code Playgroud)

这输出:

Some(3)
None
Run Code Online (Sandbox Code Playgroud)

  • 好点子.我更多地谈到他的评论,"我希望生锈可以帮助我避免这种问题",以表明生锈可以帮助他避免这个问题. (3认同)
  • 这不是对此处提出的问题的答案。 (3认同)
  • 他在问为什么要编译程序,而不是在问索引是否超出范围。 (2认同)