Как преобразовать символ char в число int в Rust, чтобы '1' стало 1?
Правильное преобразование char в число в Rust
Вы столкнулись с типичной ловушкой для новичков в Rust. Прямое приведение типа char as i32 даёт ASCII-код символа, а не его числовое значение. Для корректного преобразования цифрового символа в целое число в Rust есть несколько способов, и самый правильный — использовать метод to_digit().
Основной способ: метод to_digit()
Метод to_digit(radix) определён для типа char. Он принимает основание системы счисления (radix) от 2 до 36 и возвращает Option<u32>. Для десятичных цифр используйте основание 10:
fn main() {
let c: char = '1';
let n: u32 = c.to_digit(10).expect("Это не цифра!");
println!("{}", n); // Выведет: 1
}
Почему это правильно? Потому что:
- Метод работает не только с '0'-'9', но и с буквами для систем счисления выше 10 (например, 'a' → 10).
- Возвращает
Option, что заставляет вас обрабатывать случай, когда символ не является цифрой. - Идиоматично для Rust — использует систему типов для безопасности.
Обработка ошибок
Если вы не уверены, что символ точно цифра, лучше не использовать expect(), а обработать None:
fn main() {
let c: char = 'x';
match c.to_digit(10) {
Some(n) => println!("Число: {}", n),
None => println!("'{}' не является цифрой", c),
}
}
Преобразование в другие целочисленные типы
Метод to_digit() возвращает u32. Если вам нужно i32 или другой тип, используйте as или From/TryFrom:
let c: char = '5';
let n_u32 = c.to_digit(10).unwrap(); // u32
let n_i32 = n_u32 as i32; // безопасно, т.к. 0-9 помещается в i32
let n_i64: i64 = n_u32.into(); // From для i64
// Альтернатива: сразу в i32 через map
let n_i32: i32 = c.to_digit(10)
.map(|d| d as i32)
.expect("Не цифра");
println!("{}", n_i32); // 5
Обработка строки целиком
Если вам нужно преобразовать всю строку цифр в число, не делайте это посимвольно. Используйте str::parse():
fn main() {
let s = "123";
let n: i32 = s.parse().expect("Не число");
println!("{}", n); // 123
}
Это работает для целых чисел, чисел с плавающей точкой и других типов, реализующих FromStr.
Старый способ (не рекомендуется)
Раньше иногда использовали вычитание кода символа '0':
let c: char = '7';
let n = c as u32 - '0' as u32; // 7
Это работает, но менее безопасно: если c не цифра, вы получите мусор. Всегда используйте to_digit() — это современный, безопасный и идиоматичный способ.
Итог
Для преобразования отдельного символа-цифры в число в Rust используйте char::to_digit(10). Он возвращает Option<u32>, что заставляет вас корректно обрабатывать ошибки. Для строк из нескольких цифр применяйте str::parse().
Альтернативный подход: использование match для явного отображения
Если вы работаете только с десятичными цифрами и хотите максимально явного контроля, можно использовать сопоставление с образцом:
fn char_to_digit(c: char) -> Option<u32> {
match c {
'0' => Some(0),
'1' => Some(1),
'2' => Some(2),
'3' => Some(3),
'4' => Some(4),
'5' => Some(5),
'6' => Some(6),
'7' => Some(7),
'8' => Some(8),
'9' => Some(9),
_ => None,
}
}
fn main() {
let c = '4';
if let Some(n) = char_to_digit(c) {
println!("{}", n); // 4
}
}
Этот код полностью эквивалентен to_digit(10), но более многословен. Его преимущество — наглядность для новичков и возможность добавить специфичную логику (например, логирование или дополнительные проверки).
Однако для production-кода лучше использовать встроенный to_digit(), так как он короче, оптимизирован компилятором и не содержит риска опечаток. Ручной match оправдан только в учебных целях или если вам нужно обрабатывать нестандартные символы (например, арабские цифры или римские числа).
Также помните, что для преобразования строки целиком всегда предпочтительнее parse(), чем посимвольная обработка — это и быстрее, и безопаснее.