【问题标题】:Why does the Rust compiler allow index out of bounds?为什么 Rust 编译器允许索引越界?
【发布时间】:2014-09-13 22:26:01
【问题描述】:

谁能解释一下为什么会这样编译:

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

运行它时,我得到:

线程 '' 在 'index out of bounds: the len is 3 but index is 4' 时惊慌失措,../src/libcollections/vec.rs:1132

【问题讨论】:

  • 可能与它不会在任何其他语言中引发编译器错误的原因相同;编译器将4 视为一个表达式,它也可能是可能返回其他值的f(x)。
  • 是的,但编译器必须看到表达式是常量文字,因此可以在编译期间检查。
  • 它可以在将来添加或作为插件添加,但它是一种优化,需要在编译时进行一些评估以了解向量的长度,并通过检查对检索元素的许多方法的调用.
  • 我猜编译器根本不知道 Vec<int> 是什么,如果你以 Vec::new() 开头,它的大小是 0 并且如果你调用 push 三次,它的size 变为 3 并且方括号中的索引必须小于向量的大小。 Vec 只是一个库类型。编译器对此没有特别的了解。
  • 编译时错误与您可以轻松证明的程序会在运行时崩溃之间是有区别的。您的程序应该只在运行时正确恐慌,这就是您编写的代码行告诉它要做的事情。也许有人可以在编译器中添加一个 lint 以在执行此操作时发出警告,但就像真的没有任何目的一样,从事编译器工作的人可以更好地把时间花在其他地方。

标签: rust


【解决方案1】:

如果您想通过索引检查访问Vec 的元素,您可以使用Vec as a slice,然后使用它的get method。例如,考虑following code。

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

这个输出:

Some(3)
None

【讨论】:

    【解决方案2】:

    为了理解这个问题,你必须从编译器看到的角度来考虑它。

    通常,编译器从不考虑表达式的值,只考虑它的类型。因此:

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

    编译器对值进行推理并非未知,并且有多种方法可以得到它。

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

    Rust 目前不支持其中的任何一个,虽然前两者已经引起了人们的兴趣,但它肯定不会在 1.0 之前完成。

    因此,在运行时检查值,Vec 的实现正确退出(此处失败)。

    【讨论】:

    • llvm 是 rustc 的优化编译器后端,但是在优化代码时确实可以看穿这些抽象层。所以我们可以看到,在这种特殊情况下,它确实将其静态编译为失败的边界检查。
    【解决方案3】:

    也许你的意思是:

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

    这将返回一个Option,因此它将返回Some 或None。比较一下:

    fn main() {
        let a = vec![1, 2, 3];
        println!("{:?}", &a[4]);
    }
    

    这通过引用访问,因此它直接访问address 并导致您的程序出现恐慌。

    【讨论】:

    • 这个答案太错误了,几乎没有什么正确的。
    • 特别... 1 a[4] 不返回Option(即slice::get)。 2 通过引用或按值访问都会导致越界恐慌。 3。 println! always borrows its arguments anyway.
    • 我明白了,对不起那些家伙,谢谢你纠正我:bow:
    猜你喜欢
    • 2015-02-17
    • 2021-02-27
    • 1970-01-01
    • 2018-06-27
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2010-10-20
    相关资源
    最近更新 更多