Перейти к содержимому

Приведение типов в 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
-3
4
255
0
65
a
1
▶ Попробуй сам

Что стоит запомнить:

  • Дробь в целое отбрасывает всё после точки. Округления нет. Если нужно ближайшее целое, сначала вызови .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 + "!");
}
▶ Попробуй сам

Сохрани три оценки за тесты как значения 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.33
▶ Попробуй сам

Магазин передаёт тебе цену текстом, "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