为什么Rust编译器允许索引越界?

irlmq6kh  于 2023-03-02  发布在  其他
关注(0)|答案(4)|浏览(130)

有人能解释一下为什么会这样吗?

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

运行时,我得到:
线程“”因“索引超出界限而死机:长度为3,但索引为4 ',../src/libcollections/vec.rs:1132

u1ehiz5o

u1ehiz5o1#

如果你想通过索引检查访问Vec的元素,你可以把Vec作为一个切片,然后使用它的get方法。

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

这将输出:

Some(3)
None
um6iljoc

um6iljoc2#

为了理解这个问题,您必须从编译器看到的Angular 来考虑它。
通常情况下,编译器从不考虑表达式的 value,而只考虑它的 type

  • a的类型为Vec<i32>
  • 4是未知的整数类型
  • Vec<i32>实现下标,因此a[4]进行类型检查

让编译器对 values 进行推理并不是未知的,并且有各种各样的方法来获得它。

  • 您可以允许在编译时计算某些表达式(例如C++ constexpr
  • 可以将值编码为类型(C++非类型模板参数,使用Peano的数字)
  • 您可以使用 dependent typing 来桥接类型和值之间差距

Rust目前并不支持其中任何一个,虽然对前两个有兴趣,但在1.0之前肯定不会这样做。
因此,在运行时检查这些值,并且Vec的实现正确地退出(这里是失败的)。

5cg8jx4n

5cg8jx4n3#

请注意,以下编译时错误:

fn main() {
    let a = [1, 2, 3];
    println!("{:?}", a[4]);
}
error: this operation will panic at runtime
 --> src/main.rs:3:22
  |
3 |     println!("{:?}", a[4]);
  |                      ^^^^ index out of bounds: the length is 3 but the index is 4
  |
  = note: `#[deny(unconditional_panic)]` on by default

这是因为如果没有vec!,类型就是[i32; 3],它实际上携带长度信息。
对于vec!,它现在是Vec<i32>类型,不再携带长度信息,它的长度只有在运行时才知道。

hc8w905p

hc8w905p4#

也许你的意思是:

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

这将返回一个Option,因此它将返回SomeNone

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

这是通过引用访问的,因此它直接访问address,并导致程序死机。

相关问题