We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ground Rules: Values, Types, Control Flow step 3 of 24
Integer types: widths, signedness and usize
For each i64, say whether it would fit in a u8 without changing value.
pub fn fits_in_u8(values: &[i64]) -> Vec<bool>
[0, 255, 256, -1] becomes [true, true, false, false].
The starter is correct. It fails the gate, and the reason is worth more than the answer.
Rust makes you pick a width
Most languages hand you one integer type and hide the rest. Rust gives you twelve, arranged in a grid you can read off in ten seconds:
| bits | signed | unsigned | unsigned max |
|---|---|---|---|
| 8 |
i8 |
u8 |
255 |
| 16 |
i16 |
u16 |
65 535 |
| 32 |
i32 |
u32 |
4 294 967 295 |
| 64 |
i64 |
u64 |
18 446 744 073 709 551 615 |
| 128 |
i128 |
u128 |
~3.4 × 10^38 |
| pointer |
isize |
usize |
machine word |
i32 is the default: an integer literal with nothing to pin it down becomes
i32. i128 and u128 really are 16 bytes each, and they really do work.
Every one of these types carries its own MIN and MAX associated constants —
u8::MAX is 255, i32::MIN is -2147483648. Use them. A literal 255
in your source says “the number two hundred and fifty-five”; u8::MAX says
“the largest value a byte can hold”, which is what you actually mean, and which
stays correct if the type ever changes.
usize is the indexing type, and that explains a lot
usize is as wide as a pointer — 8 bytes on the 64-bit machines that grade
this course. It is the type of:
-
.len()on every slice,Vec,Stringand array; -
every index you can use with
[]; - every capacity, offset and count in the standard library.
This is why items[i as i32] in the previous problem was E0277 and not a
warning: Index is implemented for usize and for ranges, and simply is not
implemented for i32. Once you know usize is the indexing type, a whole
family of otherwise baffling trait errors becomes one rule.
It is also why for i in 0..v.len() gives you a usize for free, and why
casting it back and forth is almost always a sign you should be iterating
instead.
Widening is a conversion, not a coercion
Rust will not silently widen. A u8 does not become an i64 because the
context wants one. You ask:
let hi = i64::from(u8::MAX); // 255i64 — always exact, cannot fail
i64::from exists precisely because every u8 value is representable as an
i64. Conversions that can lose information do not get a From; they get a
TryFrom that returns a Result, which is item 1.11. The type system encodes
which conversions are safe, and refuses to let you conflate the two.
The lint you will meet
The starter writes the interval test by hand:
v >= 0 && v <= 255
Clippy’s manual_range_contains fires on that and suggests
(0..=255).contains(&v). It is on by default, it is a style lint, and its
argument is that a range says “this interval” as one idea rather than as two
comparisons a reader has to re-assemble — and that it is much harder to get the
inclusive/exclusive ends wrong.
Combine both lessons: build the range out of u8::MIN and u8::MAX, widened
to i64, and ask it whether it contains the value.
One more lint, for later
absurd_extreme_comparisons is a correctness lint, denied by default, and it
catches things like x >= 0 where x is unsigned — a test that is always true
and therefore almost certainly a bug in the reasoning. It will not fire here
because our values are i64, but remember it exists the first time you write a
bounds check against an unsigned type.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.