Конвертация String в int в Rust: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему Rust не даёт просто так взять и конвертировать строку в число?

Если вы пришли из Python или JavaScript, то привыкли к магии вроде int("42") или parseInt("42"). В Rust такой фокус не пройдёт — компилятор потребует чётко указать, в какой именно тип вы хотите превратить строку. Почему? Потому что Rust — это язык, который не прощает небрежности. Он заставляет вас думать о граничных случаях: что если в строке окажется не число? Что если число слишком большое для выбранного типа?

В этой статье мы разберём самый популярный вопрос на Stack Overflow среди новичков в Rust: как преобразовать String в int. Вы получите не просто готовый код, но и полное понимание того, что происходит под капотом.

Метод parse() — главный инструмент конвертации

Основной способ преобразования строки в число в Rust — это метод parse(), который доступен для типа String и &str. Он реализован через типаж FromStr и возвращает Result<T, E>.

Базовый пример: String → i32

fn main() {
    let number_string = String::from("42");
    let number: i32 = number_string.parse().unwrap();
    println!("Число: {}", number); // Вывод: Число: 42
}

Обратите внимание на unwrap(). Это быстрый способ «достать» значение из Result, но он опасен: если строка не является числом, программа запаникует и упадёт.

Правильная обработка ошибок

В реальном коде вы никогда не должны использовать unwrap() бездумно. Вот как делать правильно:

use std::num::ParseIntError;

fn main() {
    let input = String::from("hello");
    
    match input.parse::<i32>() {
        Ok(number) => println!("Успешно: {}", number),
        Err(e) => println!("Ошибка конвертации: {}", e),
    }
}

Или более лаконичный вариант с if let:

fn main() {
    let input = String::from("2024");
    
    if let Ok(year) = input.parse::<i32>() {
        println!("Год: {}", year);
    } else {
        println!("Не удалось распарсить строку");
    }
}

Доступные целочисленные типы для конвертации

Rust предлагает богатый выбор целочисленных типов. Вы можете конвертировать строку в любой из них:

  • i8, i16, i32, i64, i128 — знаковые целые
  • u8, u16, u32, u64, u128 — беззнаковые целые
  • isize, usize — размер зависит от архитектуры

Пример конвертации в разные типы:

fn main() {
    let val = "255";
    
    let a: u8  = val.parse().unwrap();   // 255
    let b: i16 = val.parse().unwrap();   // 255
    let c: u32 = val.parse().unwrap();   // 255
    
    // А вот так будет ошибка — 255 не влезает в i8
    // let d: i8 = val.parse().unwrap(); // PANIC!
}

Продвинутые техники: from_str и пользовательские типы

Метод parse() внутри вызывает from_str() из типажа FromStr. Вы можете реализовать этот типаж для своих структур:

use std::str::FromStr;
use std::num::ParseIntError;

#[derive(Debug)]
struct Version {
    major: u32,
    minor: u32,
}

impl FromStr for Version {
    type Err = ParseIntError;
    
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split('.').collect();
        if parts.len() != 2 {
            // Создаём свою ошибку, но для примера используем ParseIntError
            return Err("1.0".parse::<u32>().unwrap_err());
        }
        
        let major = parts[0].parse::<u32>()?;
        let minor = parts[1].parse::<u32>()?;
        
        Ok(Version { major, minor })
    }
}

fn main() {
    let version_str = String::from("3.14");
    let version: Version = version_str.parse().unwrap();
    println!("{:?}", version); // Version { major: 3, minor: 14 }
}

Работа с большими числами и переполнением

Если число в строке превышает допустимый диапазон типа, parse() вернёт ошибку, а не обрежет значение молча. Это важное отличие от некоторых других языков:

fn main() {
    let big_number = "99999999999999999999"; // 20 цифр
    
    match big_number.parse::<i32>() {
        Ok(n) => println!("{}", n),
        Err(e) => println!("Ошибка: {}", e), // number too large to fit in target type
    }
    
    // А с i128 всё ок
    let huge: i128 = big_number.parse().unwrap();
    println!("{}", huge); // 99999999999999999999
}

Парсинг строк с пробелами и префиксами

Метод parse() чувствителен к формату. Пробелы или префиксы 0x (шестнадцатеричные) не поддерживаются по умолчанию:

fn main() {
    // Это не сработает:
    // let a: i32 = "  42  ".parse().unwrap(); // Ошибка!
    // let b: i32 = "0x1F".parse().unwrap();   // Ошибка!
    
    // Решение: предварительная очистка
    let dirty = String::from("  42  ");
    let clean = dirty.trim();
    let number: i32 = clean.parse().unwrap();
    println!("{}", number); // 42
    
    // Для шестнадцатеричных используйте специальные методы
    let hex = "1F";
    let value = i32::from_str_radix(hex, 16).unwrap();
    println!("{}", value); // 31
}

Сравнение с другими языками: таблица для наглядности

Чтобы закрепить, вот как выглядит конвертация строки в число в разных языках:

// Python — магия, но без типов
number = int("42")

// JavaScript — тоже магия
let num = parseInt("42");

// Rust — явно и безопасно
let number: i32 = "42".parse().unwrap();

Каждый подход имеет свои плюсы и минусы. Rust выбирает явность и безопасность ценой дополнительной строки кода.

Частые ошибки и как их избежать

  1. Забыли указать тип: "42".parse() — компилятор не может вывести тип, нужно аннотировать.
  2. Не

Блоги

Рекомендаций по книгам