🦀 Rust

Wörterbücher und Hash-Tabellen in Rust 1.75: Ausführliche Anleitung

Словари и хеш-таблицы в Rust

Что такое словарь и зачем он нужен?

Представь, что у тебя есть список друзей, и ты хочешь быстро найти номер телефона по имени. Если бы ты хранил всё в обычном списке, тебе пришлось бы просматривать каждую запись, пока не найдёшь нужную. Это долго и неудобно.

Словарь (в Rust он называется HashMap) — это как волшебная записная книжка. В ней каждая запись состоит из двух частей: ключа (например, имя друга) и значения (например, номер телефона). Когда ты хочешь найти номер, ты просто говоришь "дай мне номер по имени 'Анна'" — и компьютер мгновенно находит ответ.

Словари очень быстрые, потому что они используют хеш-таблицу. Хеш-таблица — это как супер-умный шкаф с ячейками. Компьютер превращает ключ (например, слово "Россия") в короткий код (хеш) и кладёт значение в ячейку с этим номером. Чтобы найти значение, нужно снова вычислить хеш ключа — и сразу попасть в нужную ячейку!

Основной синтаксис

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

use std::collections::HashMap;

Теперь создадим пустой словарь:

let mut spravochnik = HashMap::new();

Добавим в него записи. Ключи и значения могут быть разными типами, но все ключи должны быть одного типа, и все значения — одного типа.

spravochnik.insert(String::from("Анна"), String::from("123-456"));
spravochnik.insert(String::from("Борис"), String::from("789-012"));

Чтобы получить значение по ключу, используем метод get. Он возвращает Option — либо Some(&значение), если ключ есть, либо None, если нет.

match spravochnik.get("Анна") {
    Some(nomer) => println!("Номер Анны: {}", nomer),
    None => println!("Контакт не найден"),
}

Можно проверить, есть ли ключ в словаре:

if spravochnik.contains_key("Борис") {
    println!("Борис есть в справочнике!");
}

Удалить запись:

spravochnik.remove("Борис");

Перебрать все записи:

for (klyuch, znachenie) in &spravochnik {
    println!("{}: {}", klyuch, znachenie);
}

Пример: Приветствия для путешественника

Создадим словарик приветствий для разных стран:

use std::collections::HashMap;
use std::io;

fn main() {
    let mut privetstviya = HashMap::new();
    privetstviya.insert(String::from("Россия"), String::from("Здравствуйте!"));
    privetstviya.insert(String::from("Англия"), String::from("Hello!"));
    privetstviya.insert(String::from("Франция"), String::from("Bonjour!"));
    privetstviya.insert(String::from("Испания"), String::from("¡Hola!"));

    println!("Введите название страны:");
    let mut strana = String::new();
    io::stdin().read_line(&mut strana).expect("Ошибка чтения");
    let strana = strana.trim();

    match privetstviya.get(strana) {
        Some(privet) => println!("В {} говорят: {}", strana, privet),
        None => println!("Извините, я не знаю приветствия для этой страны."),
    }
}

Пример: Телефонный справочник

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

use std::collections::HashMap;
use std::io;

fn main() {
    let mut telefon = HashMap::new();
    telefon.insert(String::from("Мария"), String::from("+7-912-345-67-89"));
    telefon.insert(String::from("Иван"), String::from("+7-903-456-78-90"));
    telefon.insert(String::from("Елена"), String::from("+7-916-567-89-01"));

    println!("Введите имя для поиска:");
    let mut imya = String::new();
    io::stdin().read_line(&mut imya).expect("Ошибка");
    let imya = imya.trim();

    match telefon.get(imya) {
        Some(nomer) => println!("Номер {}: {}", imya, nomer),
        None => println!("Абонент '{}' не найден.", imya),
    }
}

Пример: Книжная карточка дел на неделю

Добавляем дела для каждого дня:

use std::collections::HashMap;
use std::io;

fn main() {
    let mut plan = HashMap::new();
    plan.insert(String::from("Понедельник"), String::from("Уборка, зарядка"));
    plan.insert(String::from("Вторник"), String::from("Магазин, готовка"));
    plan.insert(String::from("Среда"), String::from("Чтение, прогулка"));

    println!("Введите день недели:");
    let mut den = String::new();
    io::stdin().read_line(&mut den).expect("Ошибка");
    let den = den.trim();

    match plan.get(den) {
        Some(dela) => println!("Дела на {}: {}", den, dela),
        None => println!("На этот день дел нет."),
    }
}

Пример: Удаление контакта из блокнота

use std::collections::HashMap;
use std::io;

fn main() {
    let mut bloknot = HashMap::new();
    bloknot.insert(String::from("Анна"), String::from("111-111"));
    bloknot.insert(String::from("Петр"), String::from("222-222"));
    bloknot.insert(String::from("Ольга"), String::from("333-333"));

    println!("Какой контакт удалить?");
    let mut imya = String::new();
    io::stdin().read_line(&mut imya).expect("Ошибка");
    let imya = imya.trim();

    if bloknot.remove(imya).is_some() {
        println!("Контакт '{}' удалён.", imya);
    } else {
        println!("Контакт '{}' не найден.", imya);
    }

    println!("Остались контакты:");
    for (k, v) in &bloknot {
        println!("{}: {}", k, v);
    }
}

Пример: Список товаров магазина

use std::collections::HashMap;

fn main() {
    let mut tovary = HashMap::new();
    tovary.insert(String::from("Хлеб"), 50);
    tovary.insert(String::from("Молоко"), 80);
    tovary.insert(String::from("Яблоки"), 120);

    println!("Список товаров и цены:");
    for (tovar, cena) in &tovary {
        println!("{}: {} рублей", tovar, cena);
    }
}

Частые ошибки новичков

  • Забыть подключить HashMap. Всегда пиши use std::collections::HashMap; в начале.
  • Использовать строки без String::from. В Rust строки по умолчанию — это &str, а в словарь нужно класть String. Пиши String::from("текст").
  • Забыть mut. Если ты хочешь добавлять или удалять записи, словарь должен быть изменяемым: let mut dict = HashMap::new();.
  • Не обрабатывать Option. Метод get возвращает Option. Всегда используй match или if let, чтобы проверить, есть ли значение.
  • Думать, что порядок сохраняется. В HashMap порядок записей не определён. Если нужен порядок, используй BTreeMap.

Итоговый пример: Сборник контактов

Объединим всё, что узнали: добавим несколько контактов, найдём один, удалим другой и выведем всё на экран.

use std::collections::HashMap;
use std::io;

fn main() {
    let mut kontakty = HashMap::new();
    kontakty.insert(String::from("Алиса"), String::from("+1-555-1234"));
    kontakty.insert(String::from("Боб"), String::from("+1-555-5678"));
    kontakty.insert(String::from("Чарли"), String::from("+1-555-9012"));

    println!("Поиск контакта. Введите имя:");
    let mut poisk = String::new();
    io::stdin().read_line(&mut poisk).expect("Ошибка");
    let poisk = poisk.trim();

    match kontakty.get(poisk) {
        Some(nom) => println!("Найден: {} - {}", poisk, nom),
        None => println!("Не найден."),
    }

    println!("Введите имя для удаления:");
    let mut udalit = String::new();
    io::stdin().read_line(&mut udalit).expect("Ошибка");
    let udalit = udalit.trim();

    if kontakty.remove(udalit).is_some() {
        println!("Удалён.");
    } else {
        println!("Такого контакта нет.");
    }

    println!("Оставшиеся контакты:");
    for (imya, telefon) in &kontakty {
        println!("{}: {}", imya, telefon);
    }
}

Словари — мощный инструмент. Они помогают хранить данные парами "ключ-значение" и быстро их находить. Используй их, когда нужно связать одно с другим: имя с номером, страну с приветствием, день недели с делами. Удачи в программировании!