Тип HashSet представляет множество - коллекцию, которая хранит только уникальные элементы. Данный тип определен в модуле std::collections:
use std::collections::HashSet;
Тип HashSet типизируется типом элементов, которые помещаются во множество:
let mut my_set: HashSet<i32>;
В данном случае множество my_set предназначено для хранения значений типа i32.
Для создания пустого множества можно использовать метод new():
let mut my_set: HashSet<i32> = HashSet::new();
Можно создать множество на основе других коллекций, например, вектора и массива
use std::collections::HashSet;
fn main() {
let my_vector = vec![1, 2, 3, 4];
let my_set: HashSet<i32> = my_vector.into_iter().collect(); // множество из вектора
println!("my_set: {:?}", my_set); // my_set: {1, 3, 2, 4}
let my_array = [5, 6, 7];
let my_set2 = HashSet::from(my_array); // множество из массива
println!("my_set2: {:?}", my_set2); // my_set2: {5, 6, 7}
}
Обратите внимание, что множество может содержать только уникальные значения. Поэтому если мы добавляем во множество повторяющиеся значения или создаем множество на основе наборов, которые содержат повторяющиеся значения, то такое множество все равно будет содержать только уникальные значения:
use std::collections::HashSet;
fn main() {
let my_set = HashSet::from([1, 2, 3, 4, 5, 3, 2, 4]);
println!("my_set: {:?}", my_set); // my_set: {4, 3, 1, 5, 2}
}
Для получения длины множества применяется встроенная функция len():
use std::collections::HashSet;
fn main() {
let my_set = HashSet::from([1, 2, 3, 4, 5]);
println!("my_set len: {}", my_set.len()); // my_set len: 5
}
Для добавления одиночного элемента вызывается метод insert():
use std::collections::HashSet;
fn main() {
let mut users: HashSet<&str> = HashSet::new();
users.insert("Tom");
users.insert("Bob");
users.insert("Sam");
println!("{:?}", users); // {"Tom", "Bob", "Sam"}
}
Стоит отметить, что для изменения множества (как и для изменения других значений) переменная множества должна быть объявлена с ключевым словом mut
Для удаления одного элемента вызывается метод remove(), в который передается удаляемый элемент. Причем удаляемый элемент должен передаваться как ссылка:
use std::collections::HashSet;
fn main() {
let mut users = HashSet::from(["Tom", "Bob", "Alice"]);
users.remove("Tom");
users.remove("Sam"); // "Sam" нет в множестве, поэтому никакого эффекта не происходит
println!("{:?}", users); // {"Bob", "Alice"}
}
Стоит отметить, что здесь множество хранит ссылки &str, так как строка по умолчанию представляет данный тип. Однако если элементы не представляют ссылки, то нам надо указывать символ ссылки (амперанд):
use std::collections::HashSet;
fn main() {
let mut numbers = HashSet::from([1, 2, 3, 4]);
numbers.remove(&2);
println!("{:?}", numbers); // {3, 1, 4}
}
Для удаления всех элементов вызывается метод clear():
let mut users = HashSet::from(["Tom", "Bob", "Alice"]); users.clear();
Для перебора элементов можно использовать цикл for:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
for user in &users{
println!("{}", user);
}
}
При переборе каждый элемент помещается в переменную user.
Метод union() объединяет два множества:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let users2 = HashSet::from(["Sam", "Kate", "Bob"]);
let users3: HashSet<_> = users.union(&users2).collect();
println!("{:?}", users3); // {"Sam", "Bob", "Alice", "Kate", "Tom"}
}
Пересечение множеств позволяет получить только те элементы, которые есть одновременно в обоих множествах. Метод intersection() производит операцию пересечения множеств:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let users2 = HashSet::from(["Sam", "Kate", "Bob"]);
let users3: HashSet<_> = users.intersection(&users2).collect();
println!("{:?}", users3); // {"Bob"}
}
Еще одна операция - разность множеств возвращает те элементы, которые есть в первом множестве, но отсутствуют во втором. Для получения разности множеств можно использовать метод difference():
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let users2 = HashSet::from(["Sam", "Kate", "Bob"]);
let users3: HashSet<_> = users.difference(&users2).collect();
println!("{:?}", users3); // {"Alice", "Tom"}
}
Отдельная разновидность разности множеств - симметрическая разность производится с помощью метода symmetric_difference(). Она возвращает все элементы обоих множеств за исключением общих:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let users2 = HashSet::from(["Sam", "Kate", "Bob"]);
let users3: HashSet<_> = users.symmetric_difference(&users2).collect();
println!("{:?}", users3); // {"Tom", "Kate", "Alice", "Sam"}
}
Метод is_subset позволяет выяснить, является ли текущее множество подмножеством (то есть частью) другого множества:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let superusers = HashSet::from(["Sam", "Tom", "Bob", "Alice", "Kate"]);
println!("{}", users.is_subset(&superusers)); // true
println!("{}", superusers.is_subset(&users)); // false
}
Метод is_superset(), наоборот, возвращает true, если текущее множество является надмножеством (то есть содержит) для другого множества:
use std::collections::HashSet;
fn main() {
let users = HashSet::from(["Tom", "Bob", "Alice"]);
let superusers = HashSet::from(["Sam", "Tom", "Bob", "Alice", "Kate"]);
println!("{}", users.is_superset(&superusers)); // false
println!("{}", superusers.is_superset(&users)); // true
}
Это только небольшой перечень методов HashSet. Полный список методов можно найти в документации на странице https://doc.rust-lang.org/std/collections/struct.HashSet.html.