An odd situation

The code below is built successfully with rust 1.43.0 in https://play.rust-lang.org/?version=stable&mode=release&edition=2018.

// success
fn main() {
    let mut numbers: [Option<u16>; 5] = [Some(0); 5];
    
    for iter in 0..5 {
        let number_to_add: u16 = 1;
        numbers[iter] = Some(number_to_add);
    }
}

After a little change, it built failed.

// failed
fn main() {
    let mut numbers: [Option<u16>; 5] = [Some(0); 5];
    
    for iter in 0..5 {
        let number_to_add: u16 = iter * 1; // changed
        numbers[iter] = Some(number_to_add);
    }
}

with error:

Compiling playground v0.0.1 (/playground)
error[E0277]: the type `[std::option::Option<u16>]` cannot be indexed by `u16`
 --> src/main.rs:6:9
  |
6 |         numbers[iter] = Some(number_to_add);
  |         ^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
  |
  = help: the trait `std::slice::SliceIndex<[std::option::Option<u16>]>` is not implemented for `u16`
  = note: required because of the requirements on the impl of `std::ops::Index<u16>` for `[std::option::Option<u16>]`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

The numbers[iter] = Some(number_to_add); line didn't change either way.

This is a consequence of two things:

  • The type of a numeric literal is inferred based on its usage.
  • Ranges can yield any type of number, not just usize.

In your original example, the only usage of iter is as an index into numbers, so the compiler infers the type of iter to be usize.

In your second example, you use iter as part of a calculation with a u16, so it infers the type of iter to also be u16. You then try to use that u16 to index into numbers, which is invalid.

2 Likes

Thanks @17cupsofcoffee , thanks warm community~

6 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.