4

The range in a for-loop, as I understand, is lower-limit inclusive and upper-limit exclusive. This is introducing an issue in the following code:

fn main() {
    let a: u8 = 4;

    for num in 0..256 {
        if num == a {
            println!("match found");
            break;
        }
    }
}

I want to loop 256 times from 0 to 255, and this fits into the range of data supported by u8. But since the range is upper limit exclusive, I have to give 256 as the limit to process 255. Due to this, the compiler gives the following warning.

warning: literal out of range for u8
 --> src/main.rs:4:19
  |
4 |     for num in 0..256 {
  |                   ^^^
  |
  = note: #[warn(overflowing_literals)] on by default

When I execute this, the program skips the for loop.

In my opinion, the compiler has to ignore 256 in the range and accept the range as u8 range. Is it correct? Is there any other way to give the range?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Steve
  • 111
  • 4

3 Answers3

6

You can combine iterators to create full u8 range:

use std::iter::once;
for i in (0..255).chain(once(255)){
    //...
}

In nightly Rust you can use inclusive range:

#![feature(inclusive_range_syntax)]
for i in 0...255 {
    //...
}
aSpex
  • 4,790
  • 14
  • 25
5

As alex already said, it's probably the best to iterate using bigger integer types (like u32) and cast it when comparing to the u8 you're searching for:

let a: u8 = 4;

for num in 0..256 {
    if (num as u8) == a {
        println!("match found");
        break;
    }
}

In this special case you can use a half-open range, too:

let a: u8 = 4;

for num in 0.. {
    if num == a {
        println!("match found");
        break;
    }
}

Also when I execute this, the program skips the for loop.

The binary representation of 256 is 1_0000_0000. u8 only saves the 8 rightmost bits, so just 0s. Thus 0..256u8 is equivalent to 0..0, which of course is an empty range.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • The half-open range is what I need. But without the break, it creates an infinite loop, so one needs to be careful. The half-open range is missing in Rust documentation? – Steve Nov 04 '16 at 11:55
  • @Steve: It is called [`RangeFrom`](https://doc.rust-lang.org/std/ops/struct.RangeFrom.html). There's also `RangeTo` and `RangeFull`. – Matthieu M. Nov 04 '16 at 12:27
  • The idea of using a half-open range is quite interesting, I wonder if it obviates part of the need for an inclusive range. – Matthieu M. Nov 04 '16 at 12:27
  • Still I think there should be a way in the language to express the full u8 range without the use of typecast. – Steve Nov 04 '16 at 12:32
  • @Steve I think many agree. But this is a huge debate in the community already, usually about syntax. Better not start a new discussion here in the comments :P – Lukas Kalbertodt Nov 04 '16 at 12:35
0

I think you are comparing different types so need to cast. Try this:

for num in 0..256 {
    let y = num as u8;
    if y == a {
        println!("found");
        break;
    }
}
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
Alex
  • 483
  • 1
  • 12
  • 23
  • That is not exactly the issue here. The fact that the range `0..256` was inferred to have elements of the same type as `a` was what brought the compilation warning in the first place. – E_net4 Nov 04 '16 at 11:38
  • @E_net4 Actually, it works (I tested at least my casting version). Apparently an `as`-cast is not a valid hint for the compiler to infer the type. So in this example, it's probably a `Range`. – Lukas Kalbertodt Nov 04 '16 at 11:40
  • @LukasKalbertodt I didn't say that this solution doesn't work. The problem is in the exposed reason, which is... well, prone to ambiguities. – E_net4 Nov 04 '16 at 11:43
  • so using `as` is not appropriate in this case? Lucas you say it is not a valid hint for compiler can you explain why? – Alex Nov 04 '16 at 13:51
  • @alex What actually happens is that `num as u8` tells the compiler that a cast from the range's element type to `u8` is needed, and "cuts" the type inference that would have occurred without it. Instead of assuming that `num` has the same type of `a`, and so inferring the range to a `Range`, it just "falls back" to `Range`. – E_net4 Nov 04 '16 at 19:07