Uh oh. If you have to turn off subscript checking in Rust for "performance" for simple loop iteration, something is very wrong.
The way this ought to work is by the compiler hoisting checks out of the loop. Consider
let mut v = vec![1i32, 2, 3, 4, 5];
let vlen = v.len()
for i in range(0, vlen) {
let x = &mut v[i];
// do some work with x
}(Have to double space due to lack of formatting capabilities here.)
Subscript checking requires something comparable to
"assert(i >= 0 && i < v.len())" at the subscript check v[i]
The compiler, knowing how "for" works, can hoist that check out of the loop, so it becomes
"assert(0 >= 0 && vlen-1 < v.len())"
at the the top of the loop, before the FOR statement is entered. Now the check only has to be executed once. This optimization is valid for all iterative FOR loops where the iteration variable and the array are not modified within the loop, and the compiler has to check that.
Then, after hoisting, some algebraic simplification can be applied to the expression in the assert. This requires a small theorem prover, or more cheaply, some rewrite rules for the common cases.
"assert(true && vlen <= v.len())" "assert(vlen <= v.len())"
Now, flow analysis shows that, at the point of the assert, vlen = v.len(). So we get
"assert(v.len() <= v.len())"
and finally
"assert(true)"
which is eliminated as dead code. Zero overhead for subscript checking, yet proved correct.
Now that's how it ought to work. One of the Go compilers does this for simple loops like this. Sprinkling "unsafe" around, and making people use funny library constructs for simple loops, is doing it wrong.
This seems to be a forgotten technology. There were Pascal compilers in the 1980s which did this. In practice, about 95% of subscript checks could be optimized out for Pascal. You can almost always get checks out of iterative inner loops, which is where they really matter.