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