We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ground Rules: Values, Types, Control Flow step 10 of 24
Casting with as: truncation, sign reinterpretation, saturation
Convert each input from i64 to u8, then back to i64. Return the resulting
values in the same order, keeping duplicates. Empty input returns an empty
vector, and every i64 input is valid.
pub fn cast_report(values: &[i64]) -> Vec<i64>
| Input | After conversion to u8 | Returned i64 |
|---|---|---|
| 300 | 44 | 44 |
| -1 | 255 | 255 |
| 0 | 0 | 0 |
| 256 | 0 | 0 |
| -256 | 0 | 0 |
The narrowing step intentionally discards information. Every output is between 0 and 255. Mathematically, it is the input's nonnegative remainder modulo 256. Widening afterward cannot restore the discarded bits.
Narrowing keeps the low bits
value as u8 keeps the lowest eight bits of the integer. For 300, that leaves
44. Negative integers use two's complement, so the low eight bits of -1 are
all ones, representing 255 as a u8.
Use i64::from(byte) to widen the result. Every u8 fits in i64, so this
conversion preserves its value exactly. Here is a complete example:
fn main() {
let original = 300_i64;
let byte = original as u8;
let widened = i64::from(byte);
assert_eq!(byte, 44);
assert_eq!(widened, 44);
assert_eq!((-1_i64) as u8, 255);
}
These integer casts have defined results in both debug and optimized builds. They do not perform an overflow check like integer arithmetic can.
Signed and unsigned conversions
When an integer cast increases the width, the source type determines how the new bits are filled. An unsigned source gets zero bits; a signed source repeats its sign bit. A same-width cast keeps all bits, but changing signedness can change the value those bits represent.
fn main() {
assert_eq!(255_u8 as u16, 255);
assert_eq!((-1_i8) as i32, -1);
assert_eq!((-1_i8) as u32, u32::MAX);
assert_eq!(255_u8 as i8, -1);
}
In the third assertion, sign extension produces 32 one-bits. The unsigned
destination interprets them as u32::MAX. In the last assertion, the unchanged
byte 0xff represents -1 as an i8.
Choose between truncating and checking
as supports specific conversions; it is not a general conversion or parsing
function. For example, "300" as u8 is a compile error. Supported numeric
casts produce values directly rather than returning a Result.
If a program should reject integers outside 0..=255, use u8::try_from:
fn main() {
assert_eq!(u8::try_from(42_i64), Ok(42));
assert!(u8::try_from(300_i64).is_err());
assert!(u8::try_from(-1_i64).is_err());
}
That is a different contract from this exercise, which deliberately keeps the low eight bits instead of rejecting out-of-range inputs.
Float-to-integer casts use different rules
The function you are implementing takes only integers. When you encounter float casts elsewhere, do not apply the low-bit rule to them. Float-to-integer casts truncate the fractional part toward zero, saturate out-of-range values to the destination's bounds, and convert NaN to zero.
// This example deliberately demonstrates the result of casting NaN.
#[allow(clippy::cast_nan_to_int)]
fn main() {
assert_eq!(3.99_f64 as i32, 3);
assert_eq!((-3.99_f64) as i32, -3);
assert_eq!(1e10_f64 as i32, i32::MAX);
assert_eq!((-1e10_f64) as i32, i32::MIN);
assert_eq!(f64::INFINITY as i32, i32::MAX);
assert_eq!(f64::NEG_INFINITY as i32, i32::MIN);
assert_eq!(f64::NAN as i32, 0);
assert_eq!((-3.99_f64) as u8, 0);
}
Clippy normally warns about casting a known NaN literal to an integer. The example allows that one lint so it can demonstrate the conversion rule.
Fix the starter's behavior and lint
The starter returns each original value unchanged. Its v as i64 cast does
nothing because v is already an i64, and Clippy's default
unnecessary_cast lint rejects it when warnings are treated as errors.
Removing that cast alone would still leave the function's result wrong.
Clippy has additional opt-in checks, including cast_possible_truncation
and cast_sign_loss in its pedantic group. Their concerns are intentional
in this exercise. A clean default lint run does not mean every conversion
preserves values; choose the conversion based on the behavior you need.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.