Casting
Rust provides no implicit type conversion (coercion) between primitive types.
But, explicit type conversion (casting) can be performed using the as
keyword.
Rules for converting between integral types follow C conventions generally, except in cases where C has undefined behavior. The behavior of all casts between integral types is well defined in Rust.
// Suppress all warnings from casts which overflow. #![allow(overflowing_literals)] fn main() { let decimal = 65.4321_f32; // Error! No implicit conversion let integer: u8 = decimal; // FIXME ^ Comment out this line // Explicit conversion let integer = decimal as u8; let character = integer as char; // Error! There are limitations in conversion rules. // A float cannot be directly converted to a char. let character = decimal as char; // FIXME ^ Comment out this line println!("Casting: {} -> {} -> {}", decimal, integer, character); // when casting any value to an unsigned type, T, // T::MAX + 1 is added or subtracted until the value // fits into the new type // 1000 already fits in a u16 println!("1000 as a u16 is: {}", 1000 as u16); // 1000 - 256 - 256 - 256 = 232 // Under the hood, the first 8 least significant bits (LSB) are kept, // while the rest towards the most significant bit (MSB) get truncated. println!("1000 as a u8 is : {}", 1000 as u8); // -1 + 256 = 255 println!(" -1 as a u8 is : {}", (-1i8) as u8); // For positive numbers, this is the same as the modulus println!("1000 mod 256 is : {}", 1000 % 256); // When casting to a signed type, the (bitwise) result is the same as // first casting to the corresponding unsigned type. If the most significant // bit of that value is 1, then the value is negative. // Unless it already fits, of course. println!(" 128 as a i16 is: {}", 128 as i16); // In boundary case 128 value in 8-bit two's complement representation is -128 println!(" 128 as a i8 is : {}", 128 as i8); // repeating the example above // 1000 as u8 -> 232 println!("1000 as a u8 is : {}", 1000 as u8); // and the value of 232 in 8-bit two's complement representation is -24 println!(" 232 as a i8 is : {}", 232 as i8); // Since Rust 1.45, the `as` keyword performs a *saturating cast* // when casting from float to int. If the floating point value exceeds // the upper bound or is less than the lower bound, the returned value // will be equal to the bound crossed. // 300.0 as u8 is 255 println!(" 300.0 as u8 is : {}", 300.0_f32 as u8); // -100.0 as u8 is 0 println!("-100.0 as u8 is : {}", -100.0_f32 as u8); // nan as u8 is 0 println!(" nan as u8 is : {}", f32::NAN as u8); // This behavior incurs a small runtime cost and can be avoided // with unsafe methods, however the results might overflow and // return **unsound values**. Use these methods wisely: unsafe { // 300.0 as u8 is 44 println!(" 300.0 as u8 is : {}", 300.0_f32.to_int_unchecked::<u8>()); // -100.0 as u8 is 156 println!("-100.0 as u8 is : {}", (-100.0_f32).to_int_unchecked::<u8>()); // nan as u8 is 0 println!(" nan as u8 is : {}", f32::NAN.to_int_unchecked::<u8>()); } }