Приведение типов в Rust
Rust не преобразует один тип в другой сам: если смешать i32 и f64 в одном выражении, код не скомпилируется. Преобразовывать нужно явно. Так сделано специально: незаметные преобразования — частый источник ошибок в других языках.
Преобразование между числовыми типами через as
Заголовок раздела «Преобразование между числовыми типами через as»Чтобы привести один числовой тип к другому, используй ключевое слово as:
fn main() { let x: i32 = 10; let y: f64 = x as f64; // i32 -> f64
println!("{y}");}Это важнее, чем кажется. Попробуй разделить два целых числа без приведения, и получишь целочисленное деление вместо дробного результата, который тебе, скорее всего, был нужен:
fn main() { let a = 10; let b = 3;
println!("{}", a / b); // 3 (целочисленное деление) println!("{}", a as f64 / b as f64); // 3.3333333333333335}Приведение к меньшему типу может терять данные
Заголовок раздела «Приведение к меньшему типу может терять данные»Приведение большего типа к меньшему (например, i32 к u8) не падает — оно просто обрезает значение, и результат может удивить:
fn main() { let big: i32 = 300; let small = big as u8; // u8 вмещает только 0-255 println!("{small}"); // 44, а не 300 — значение «прокрутилось»}Приведение дробей, символов и логических значений
Заголовок раздела «Приведение дробей, символов и логических значений»as работает не только с целыми числами. Для каждого случая есть правило, которое стоит знать:
fn main() { println!("{}", 3.99_f64 as i32); // 3: дробная часть отбрасывается println!("{}", -3.99_f64 as i32); // -3: к нулю, а не вниз println!("{}", 3.99_f64.round() as i32); // 4: если нужно округление, сначала round println!("{}", 300.0_f64 as u8); // 255: слишком большое, остаётся на максимуме println!("{}", -5.0_f64 as u8); // 0: слишком маленькое, остаётся на минимуме println!("{}", 'A' as u32); // 65: числовой код символа println!("{}", 97_u8 as char); // a: и обратно println!("{}", true as i32); // 1 (false дало бы 0)}Вывод:
3-34255065a1Что стоит запомнить:
- Дробь в целое отбрасывает всё после точки. Округления нет. Если нужно ближайшее целое, сначала вызови
.round(). - Дроби вне диапазона прижимаются к ближайшему подходящему значению (
300.0вu8становится255). Это не так, как у целых чисел, которые «прокручиваются» (выше300стало44). - У символов за спиной стоит число (их кодовая точка Unicode).
'A' as u32даёт65, а'Я' as u32—1071. Напрямую обратно вcharможно привести толькоu8; для больших чисел используютchar::from_u32, потому что не каждое число — допустимый символ. - Логические значения превращаются в
1или0. В обратную сторону не работает:1 as boolне скомпилируется. Используй сравнение вродеn != 0.
Превращаем строку в число
Заголовок раздела «Превращаем строку в число»Приведение через as работает только между числовыми типами. Чтобы превратить текст в число — например, то, что ввёл пользователь, — используй .parse():
fn main() { let text = "42"; let number: i32 = text.parse().expect("это не число");
println!("{}", number + 8);}Вывод:
50.parse() может не сработать (а вдруг в тексте вообще не число?), поэтому возвращает не само число, а Result. Result мы ещё не проходили — пока .expect("сообщение") — простой способ сказать: «если не получилось, упади с этим сообщением». Как обрабатывать это правильно, показано в уроке Result.
Числа в строки
Заголовок раздела «Числа в строки»В обратную сторону всё проще: почти любой тип превращается в String через .to_string():
fn main() { let number = 42; let text = number.to_string(); println!("{}", text + "!");}Практика
Заголовок раздела «Практика»1. Средний балл
Заголовок раздела «1. Средний балл»Сохрани три оценки за тесты как значения i32: 7, 8 и 10. Выведи их сумму, а затем среднее с двумя знаками после точки. Подсказка: если разделить два целых числа, получится 8, а не 8.33, поэтому сначала приведи сумму к f64. {:.2} печатает два знака после точки.
Показать решение
fn main() { let a: i32 = 7; let b: i32 = 8; let c: i32 = 10;
let sum = a + b + c; let average = sum as f64 / 3.0; // 25.0 / 3.0, а не 25 / 3
println!("сумма: {sum}"); println!("среднее: {:.2}", average);}Вывод:
сумма: 25среднее: 8.332. Цена из текста
Заголовок раздела «2. Цена из текста»Магазин передаёт тебе цену текстом, "4.50", и количество как i32, 3. Преврати текст в f64, умножь на количество и выведи Итого: 13.5. Подсказка: понадобятся оба инструмента с этой страницы: .parse() для текста и as f64 для количества.
Показать решение
fn main() { let price_text = "4.50"; let quantity: i32 = 3;
let price: f64 = price_text.parse().expect("неверная цена"); let total = price * quantity as f64; // f64 * f64
println!("Итого: {total}");}Вывод:
Итого: 13.5Без as f64 Rust откажется умножать f64 на i32, потому что никогда не смешивает числовые типы за тебя. И ещё: .parse() ждёт точку, а не запятую — "4,50" не разберётся.
- Rust никогда не преобразует типы автоматически — приведение всегда явное.
- Для преобразования между числовыми типами используй
as:x as f64,x as u8. - Приведение к меньшему типу молча обрезает значение — ошибки не будет, так что будь внимателен.
- Дробь в целое отбрасывает дробную часть (для округления сначала
.round()).charиboolтоже можно привести к числам. .parse()превращает текст в число, а.to_string()— наоборот.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Что будет, если в Rust разделить два целых числа, например 10 / 3, без приведения?
2. Что произойдёт при 300_i32 as u8?
3. Что возвращает .parse() при превращении строки в число, раз преобразование может не удаться?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- Приведение типов — Rust на примерах: много примеров приведения через
asс комментариями о том, что получается в каждом случае (перевод на русский). - Type cast expressions — The Rust Reference (на английском): полная таблица допустимых приведений и точное правило для каждого.
- FromStr и ToString — Rust на примерах:
.to_string()и.parse()чуть подробнее (перевод на русский). TryFrom— документация стандартной библиотеки (на английском): проверяемое преобразование (u8::try_from(...)) для случаев, когда значение может не поместиться.- Numeric Types — The Rust Reference (на английском): размер и диапазон каждого целого и дробного типа.