Reference value out of the index

I found this code from 'Programming Rust' book, and I'm a little confusing about it. Take a look at this code:

fn main() {
    let v: Vec<i32> = vec![1, 2, 3];

    let temp = 1;
    for &val in v[3..].iter() {
        println!("{}", val);
        println!("{}", gcd(val, temp)); 
    }
    println!("hello world");
}

fn gcd(mut n: i32, mut m: i32) -> i32 {
    assert!(n != 0 && m != 0);
    while m != 0 {
        if m < n {
            let t = m;
            m = n;
            n = t;
        }
        m = m % n;
    }
    n
}

The highest index of the vector is 2. But why this code is not error(but if change v[4..] the error is pop out). If call the next method after consume all value the it return None but why the rust analyzer show the type of val is i32 and not None, I tried to print it but nothing come out. Even can pass in the function. Is that a null? Why rust allow this code?

A half-open range starting and ending one past the end of the vector does not include the last element (since it is an empty range). Therefore it is allowed. It is also allowed for symmetry and ease of use so that slice[0..slice.len()] is the same as slice[..].

Another useful property that this allows is that you can always split a slice into the first n elements and the remaining elements by writing:

(&slice[..n], &slice[n..])

even if n is equal to slice.len().

2 Likes

so the value copy from the slice will drop at the end of the for loop and memory is safe. Am I right?

No value is copied from the slice, v[3..] is an empty slice.

2 Likes

You in the line for &val in v[3..].iter() since you said no value is copy, but type of val is i32 so I can pass it in the function println!("{}", gcd(val, temp); . So val has no value but have the type i32? Are no value and Null difference?

println! will never be called for an empty iterator, because the loop body is skipped entirely in that case.

2 Likes

Thank you so much bro.

Code still has to pass the type checker whether it is ever executed or not. In the line for &val in v[3..].iter(), val has the type i32 because v[3..] has the type [i32], but that does not mean that val ever actually contains an i32.

This is a useful property because it means the compiler can compile the code correctly without knowing what it will actually do at runtime. The compiler does not know, when compiling that line, that v[3..] is an empty slice. This is a good thing because if the correct way to compile the code depended on whether the slice was empty or not, a lot of code wouldn't be compilable at all.

4 Likes

Thank you so much bro.