Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a range that starts at a negative number not iterate?

I have just started to learn Rust. During my first steps with this language, I found a strange behaviour, when an iteration is performed inside main or in another function as in following example:

fn myfunc(x: &Vec<f64>) {
    let n = x.len();
    println!("    n: {:?}", n);
    for i in -1 .. n {
        println!("    i: {}", i);
    }
}

fn main() {
    for j in -1 .. 6 {
        println!("j: {}", j);
    }

    let field = vec![1.; 6];
    myfunc(&field);
}

While the loop in main is correctly displayed, nothing is printed for the loop inside myfunc and I get following output:

j: -1
j: 0
j: 1
j: 2
j: 3
j: 4
j: 5
    n: 6

What is the cause of this behaviour?

like image 645
Holger Avatar asked Sep 05 '15 15:09

Holger


1 Answers

Type inference is causing both of the numbers in your range to be usize, which cannot represent negative numbers. Thus, the range is from usize::MAX to n, which never has any members.

To find this out, I used a trick to print out the types of things:

let () = -1 .. x.len();

Which has this error:

error: mismatched types:
 expected `core::ops::Range<usize>`,
    found `()`
(expected struct `core::ops::Range`,
    found ()) [E0308]
let () = -1 .. x.len();
    ^~

Diving into the details, slice::len returns a usize. Your -1 is an untyped integral value, which will conform to fit whatever context it needs (if there's nothing for it to conform to, it will fall back to an i32).

In this case, it's as if you actually typed (-1 as usize)..x.len().

The good news is that you probably don't want to start at -1 anyway. Slices are zero-indexed:

fn myfunc(x: &[f64]) {
    let n = x.len();
    println!("    n: {:?}", n);
    for i in 0..n {
        println!("    i: {}", i);
    }
}

Extra good news is that this annoyance was fixed in the newest versions of Rust. It will cause a warning and then eventually an error:

warning: unary negation of unsigned integers will be feature gated in the future
     for i in -1 .. n {
              ^~

Also note that you should never accept a &Vec<T> as a parameter. Always use a &[T] as it's more flexible and you lose nothing.

like image 73
Shepmaster Avatar answered Oct 07 '22 19:10

Shepmaster