Приведение типов
Rust не предусматривает неявного (принудительного) преобразования типов между примитивами. Однако явное преобразование типов (casting) можно выполнить, используя ключевое слово as
.
Правила, используемые для преобразования внутренних типов, такие же, как в языке C, за исключением тех случаев, когда преобразование типов в языке C вызывает неопределённое поведение. Поведение всех приведений между встроенными типами чётко определено в Rust.
// Строчка ниже убирает все предупреждения, // которые вызываются переполнением при преобразовании типов. #![allow(overflowing_literals)] fn main() { let decimal = 65.4321_f32; // Ошибка! Нет неявного преобразования let integer: u8 = decimal; // ИСПРАВЬТЕ ^ Закомментируйте данную строку // Явное преобразование let integer = decimal as u8; let character = integer as char; // Ошибка! Здесь ограничение в правилах конвертации. // Число с плавающей точкой не может быть напрямую конвертировано в символ. let character = decimal as char; // ИСПРАВЬТЕ ^ Закомментируйте данную строку println!("Преобразование: {} -> {} -> {}", decimal, integer, character); // Когда преобразовывается любое значение в беззнаковый тип T // std::T::MAX + 1 добавляется или вычитается до тех пор, пока значение // не будет помещаться в новый тип. // 1000 поместится в u16 println!("1000 as u16: {}", 1000 as u16); // 1000 - 256 - 256 - 256 = 232 // Подробнее. Первые 8 младших битов (LSB) сохраняются, // а старшие биты (MSB) будут усечены. println!("1000 as u8: {}", 1000 as u8); // -1 + 256 = 255 println!(" -1 as u8: {}", (-1i8) as u8); // Для положительных чисел результатом будет остаток от деления println!("1000 mod 256: {}", 1000 % 256); // Когда значение преобразовывается в знаковый тип, // побитовый результат будет таким же, как и // первое преобразование к соответствующему типу без знака. Если старший бит этого значения // равен 1, то это значение — отрицательное. // За исключением случая, когда значение умещается в тип. println!(" 128 as i16: {}", 128 as i16); // 128 as u8 -> 128, дополнительный код которого в 8 битах: println!(" 128 as i8: {}", 128 as i8); // повторяем примеры // 1000 as u8 -> 232 println!("1000 as u8: {}", 1000 as u8); // и дополнительный код 232 — это -24 println!(" 232 as i8: {}", 232 as i8); // Начиная с Rust 1.45, ключевое слово `as` выполняет *насыщающее приведение* (saturating cast) // при преобразовании в целое число с плавающей точкой. // Если значение числа с плавающей точкой превышает верхнюю границу // или меньше нижней границы, то возвращаемое значение // будет равняться пересечённой границе. // 300.0 == 255 println!("300.0 == {}", 300.0_f32 as u8); // -100.0 as u8 == 0 println!("-100.0 as u8 == {}", -100.0_f32 as u8); // nan as u8 is 0 println!("nan as u8 == {}", f32::NAN as u8); // Это поведение требует небольших затрат во время работы программы, // и его можно избежать при помощи unsafe-методов, однако результат // может пересечь границы, и мы получим ненадёжное значение. // Используйте эти методы с умом: unsafe { // 300.0 == 44 println!("300.0 == {}", 300.0_f32.to_int_unchecked::<u8>()); // -100.0 as u8 == 156 println!("-100.0 as u8 == {}", (-100.0_f32).to_int_unchecked::<u8>()); // nan as u8 == 0 println!("nan as u8 == {}", f32::NAN.to_int_unchecked::<u8>()); } }