Can someone explain why this compiles:
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a[4]);
}
When running it, I got:
thread '' panicked at 'index out of bounds: the len is 3 but the index is 4', ../src/libcollections/vec.rs:1132
Can someone explain why this compiles:
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a[4]);
}
When running it, I got:
thread '' panicked at 'index out of bounds: the len is 3 but the index is 4', ../src/libcollections/vec.rs:1132
If you would like to access elements of the Vec
with index checking, you can use the Vec
as a slice and then use its get
method. For example, consider the following code:
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a.get(2));
println!("{:?}", a.get(4));
}
This outputs:
Some(3)
None
In order to understand the issue, you have to think about it in terms of what the compiler sees.
Typically, a compiler never reasons about the value of an expression, only about its type. Thus:
a
is of type Vec<i32>
4
is of an unknown integral typeVec<i32>
implements subscripting, so a[4]
type checksHaving a compiler reasoning about values is not unknown, and there are various ways to get it.
const
functions and variables.const
generic parameters.Rust supports the first two since 1.51, and they could be used to get compile-time checked indexing of compile-time indexes in collections of compile-time defined length... But that would require a different interface than the Index
trait, something like a.at::<4>()
for example.
Thus, with Index
, the values are checked at runtime, and the implementation of Vec
correctly bails out (here failing).
Note that the following is a compile time error:
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
This works because without the vec!
, the type is [i32; 3]
, which does actually carry length information.
With the vec!
, it's now of type Vec<i32>
, which no longer carries length information. Its length is only known at runtime.