std::collections: Обзор структур данных
Практические советы
Пример: Комбинирование коллекций
Упражнение
Заключение
В этом разделе мы познакомимся с модулем std::collections — частью стандартной библиотеки Rust, которая предоставляет набор мощных структур данных для хранения и управления набором элементов. Мы подробно разберём динамические массивы (Vec), хэш-таблицы (HashMap и HashSet) и сбалансированные деревья (BTreeMap и BTreeSet). Лекция подойдёт как новичкам, только начинающим изучать Rust, так и опытным разработчикам, желающим углубить свои знания. Мы рассмотрим особенности, примеры использования и тонкости выбора подходящей коллекции.
std::collections: Обзор структур данныхМодуль std::collections содержит коллекции — контейнеры для хранения множества элементов. В отличие от базовых типов, таких как массивы фиксированной длины ([T; N]), коллекции в std::collections динамичны и предлагают гибкость для различных задач. Они оптимизированы для производительности и безопасности, что делает их неотъемлемой частью разработки на Rust.
Основные характеристики коллекций в Rust:
iter(), map() и filter().Давайте разберём ключевые структуры данных из std::collections, указанные в плане: Vec, HashMap, HashSet, BTreeMap и BTreeSet.
VecVec — это динамический массив, который растёт или уменьшается по мере добавления или удаления элементов. Это одна из самых часто используемых коллекций в Rust благодаря своей простоте и скорости доступа по индексу.
Особенности:
Пример: работа с Vec:
use std::collections::Vec;
fn main() {
// Создаём пустой Vec
let mut numbers: Vec = Vec::new();
// Добавляем элементы
numbers.push(1);
numbers.push(2);
numbers.push(3);
// Доступ по индексу
println!("Первый элемент: {}", numbers[0]);
// Итерация
for num in &numbers {
println!("Число: {}", num);
}
// Удаляем последний элемент
if let Some(last) = numbers.pop() {
println!("Удалён: {}", last);
}
}
Комментарии:
push добавляет элемент в конец.pop возвращает Option, так как Vec может быть пустым.get().Заметка: Используйте Vec::with_capacity(n), если заранее знаете размер, чтобы избежать частых перевыделений памяти.
HashMapHashMap — это ассоциативный массив, который хранит пары "ключ-значение". Он использует хэширование для быстрого доступа к данным по ключу.
Особенности:
Eq и Hash.Пример: подсчёт слов в тексте:
use std::collections::HashMap;
fn main() {
let text = "hello world hello rust world";
let mut word_count = HashMap::new();
// Подсчитываем слова
for word in text.split_whitespace() {
*word_count.entry(word).or_insert(0) += 1;
}
// Выводим результат
for (word, count) in &word_count {
println!("Слово '{}': {} раз", word, count);
}
}
Комментарии:
entry возвращает Entry, позволяя модифицировать значение или вставить новое.or_insert добавляет значение по умолчанию (здесь 0), если ключа нет.HashSetHashSet — это множество, которое хранит уникальные элементы без дубликатов. Оно похоже на HashMap, но без значений, только ключи.
Особенности:
Eq и Hash.Пример: удаление дубликатов:
use std::collections::HashSet;
fn main() {
let numbers = vec![1, 2, 2, 3, 3, 4];
let unique: HashSet = numbers.into_iter().collect();
println!("Уникальные числа: {:?}", unique);
}
Комментарии:
collect преобразует итератор в HashSet.BTreeMapBTreeMap — это отсортированная карта, реализованная на основе B-дерева. В отличие от HashMap, она сохраняет порядок ключей.
Особенности:
Ord.Пример: отсортированная таблица:
use std::collections::BTreeMap;
fn main() {
let mut scores = BTreeMap::new();
scores.insert("Alice", 95);
scores.insert("Bob", 87);
scores.insert("Charlie", 92);
for (name, score) in &scores {
println!("{}: {}", name, score);
}
}
Комментарии:
BTreeSetBTreeSet — это отсортированное множество, аналогичное HashSet, но с упорядоченными элементами.
Особенности:
Ord.Пример: диапазон чисел:
use std::collections::BTreeSet;
fn main() {
let mut numbers = BTreeSet::new();
numbers.insert(5);
numbers.insert(2);
numbers.insert(8);
// Элементы от 2 до 6
let range: Vec<_> = numbers.range(2..=6).collect();
println!("Диапазон: {:?}", range); // [2, 5]
}
Комментарии:
range возвращает итератор по элементам в заданном диапазоне.Предупреждение: HashMap и HashSet быстрее для случайного доступа, но BTreeMap и BTreeSet лучше для задач с упорядочиванием или диапазонами.
Vec для последовательного доступа, HashMap/HashSet для быстрого поиска, BTreeMap/BTreeSet для упорядоченности.with_capacity) для Vec, HashMap и HashSet, если размер известен.iter() и into_iter() вместо индексов для большей выразительности.Hash, Eq, Ord).Программа для подсчёта уникальных слов и их частоты:
use std::collections::{HashMap, HashSet};
fn main() {
let text = "rust is great rust is fun";
// Уникальные слова в HashSet
let unique_words: HashSet<&str> = text.split_whitespace().collect();
println!("Уникальные слова: {:?}", unique_words);
// Частота слов в HashMap
let mut word_freq = HashMap::new();
for word in text.split_whitespace() {
*word_freq.entry(word).or_insert(0) += 1;
}
println!("Частота слов: {:?}", word_freq);
}
Этот пример демонстрирует, как HashSet и HashMap решают разные задачи с одной и той же данными.
Напишите программу, которая:
Vec чисел от 1 до 10.HashSet, добавляет несколько дубликатов и выводит уникальные элементы.BTreeMap, где ключи — числа из Vec, а значения — их квадраты.BTreeMap в порядке возрастания ключей.Подсказка: Используйте collect для преобразований и iter для итерации.
Модуль std::collections предоставляет богатый набор структур данных, каждая из которых оптимизирована для своих задач. Vec хорош для последовательного хранения, HashMap и HashSet — для быстрого поиска, а BTreeMap и BTreeSet — для упорядоченных данных. Понимание их особенностей и правильный выбор — ключ к эффективному коду на Rust. В следующих разделах мы рассмотрим другие утилиты стандартной библиотеки, такие как std::fmt.
Выполните упражнение или двигайтесь дальше!