English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Коллекция (Collection) - это наиболее распространенная форма хранения данных в структурах данных, Rust стандартная библиотека предоставляет богатый набор типов коллекций, помогающих разработчикам обрабатывать операции данных в структурах данных.
Вектор (Vector) - это единственная структура данных для хранения множества значений, которая линейно хранит значения одного и того же типа в памяти.
Вектор (Vector) - это линейная таблица, в Rust она представлена как Vec<T>.
Использование векторов ähnelt использованию списков (List), и мы можем создать вектор指定анного типа таким образом:
let vector: Vec<i32> = Vec::new(); // Создание пустого вектора типа i32 let vector = vec![1, 2, 4, 8]; // Создание вектора через массив
Мы часто используем операции добавления в линейных списках, но операции добавления и операции push в стеке по сути одинаковы, поэтому вектор имеет только метод push для добавления одного элемента:
fn main() { let mut vector = vec![1, 2, 4, 8]; vector.push(16); vector.push(32); vector.push(64); println!("{:?}", vector); {}
Результат выполнения:
[1, 2, 4, 8, 16, 32, 64]
Метод append используется для подключения одного вектора к концу другого вектора:
fn main() { let mut v1: Vec<i32> = vec![1, 2, 4, 8]; let mut v2: Vec<i32> = vec![16, 32, 64]; v1.append(&mut v2); println!("{:?}", v1); {}
Результат выполнения:
[1, 2, 4, 8, 16, 32, 64]
Метод get используется для извлечения значения из вектора:
fn main() { let mut v = vec![1, 2, 4, 8]; println!("{}", match v.get(0) { Some(value) => value.to_string(), None => "None".to_string(), }); {}
Результат выполнения:
1
Поскольку длина вектора не может быть выведена логически, метод get не может гарантировать, что一定会 получить значение, поэтому возвращаемое значение метода get - это тип Option, который может быть пустым.
Это безопасный способ получения значения, но он несколько сложен в написании. Если вы можете гарантировать, что индекс значения не выходит за пределы диапазона индексов вектора, вы также можете использовать синтаксис массива для получения значения:
fn main() { let v = vec![1, 2, 4, 8]; println!("{}", v[1]); {}
Результат выполнения:
2
Но если мы пытаемся получить v[4], вектор вернет ошибку.
Итерация по вектору:
fn main() { let v = vec![100, 32, 57]; for i in &v { println!("{}", i); {} {}
Результат выполнения:
100 32 57
Если в процессе итерации необходимо изменить значение переменной:
fn main() { let mut v = vec![100, 32, 57]; for i in &mut v { *i += 50; {} {}
Тип строки (String) был использован во многих местах до сих пор, поэтому многие методы уже хорошо известны читателям. В этой главе мы рассмотрим методы строк и свойства UTF-8.
Создание новой строки:
let string = String::new();
Преобразование базовых типов в строки:
let one = 1.to_string(); // Целое число в строку let float = 1.3.to_string(); // Число с плавающей запятой в строку let slice = "slice".to_string(); // Строковый срез в строку
Строки, содержащие символы UTF-8:
let hello = String::from("السلام عليكم"); let hello = String::from("Dobrý den"); let hello = String::from("Hello"); let hello = String::from("שָׁלוֹם"); let hello = String::from("नमस्ते"); let hello = String::from("こんにちは"); let hello = String::from("안녕하세요"); let hello = String::from("你好"); let hello = String::from("Olá"); let hello = String::from("Здравствуйте"); let hello = String::from("Hola");
Приложение строк:
let mut s = String::from("run"); s.push_str("oob"); // Добавление строкового среза s.push('!'); // Добавление символа
Соединение строк с помощью знака +:
let s1 = String::from("Hello,"); let s2 = String::from("world!"); let s3 = s1 + &s2;
Эта грамматика также может включать строковые срезы:
let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let s = s1 + "-" + &s2 + "-" + &s3;
Использование макроса format!:
let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let s = format!("{}-{}-{}", s1, s2, s3);
Длина строки:
let s = "hello"; let len = s.len();
Значение len составляет 5.
let s = "你好"; let len = s.len();
Значение len составляет 6. Поскольку китайский символы являются UTF-8 кодированными, каждый символ имеет длину 3 байта, поэтому длина составляет 6. Но в Rust поддерживается объект UTF-8 символа, поэтому если нужно contar symbols, можно сначала преобразовать строку в множество символов:
let s = "hello你好"; let len = s.chars().count();
Значение len составляет 7, так как в общей сложности есть 7 символов. Счет символов выполняется значительно медленнее, чем счет длины.
Просмотр строки:
fn main() { let s = String::from("hello中文"); for c in s.chars() { println!("{}", c); {} {}
Результат выполнения:
h e l l o 中 文
Извлечение отдельного символа из строки:
fn main() { let s = String::from("EN中文"); let a = s.chars().nth(2); println!("{:?}", a); {}
Результат выполнения:
Some('中')
ВниманиеФункция nth предназначена для извлечения значения из итератора, не используйте ее в цикле итерации! Поскольку длина каждого символа UTF-8 может варьироваться!
Если нужно вырезать часть строки:
fn main() { let s = String::from("EN中文"); let sub = &s[0..2]; println!("{}", sub); {}
Результат выполнения:
EN
Но请注意,此种用法可能会破坏一个 UTF-8 символ! Это может привести к ошибке:
fn main() { let s = String::from("EN中文"); let sub = &s[0..3]; println!("{}", sub); {}
Результат выполнения:
Строка 'main' упала в ошибке 'index байта 3 не является границей символа; он находится внутри '中' (байты 2..5) строки `EN中文`, src\libcore\str\mod.rs:2069:5 note: запустите с переменной окружения `RUST_BACKTRACE=1`, чтобы отобразить отладочную информацию.
Мап (Map) широко распространен в других языках. Самым распространенным из них является хэш-мап (Hash Map).
Создайте новый хеш-таблицу с значением-мапой:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("color", "red"); map.insert("size", "10 m^2"); println!("{}", map.get("color").unwrap()); {}
Внимание: Здесь не указан генерик хеш-таблицы, потому что Rust автоматически определяет тип.
Результат выполнения:
red
Методы insert и get — это два самых часто используемых метода мап.
Мапы поддерживают итераторы:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("color", "red"); map.insert("size", "10 m^2"); for p in map.iter() { println!("{:?}", p); {} {}
Результат выполнения:
("color", "red") ("size", "10 m^2")
Итерируемые элементы представляют собой кортежи, состоящие из ключа и значения.
Мапы Rust — это очень удобная структура данных, когда с помощью метода insert добавляется новый ключ-значение, если уже существует одинаковый ключ, он заменяет соответствующее значение. Если вы хотите "безопасно вставить", то есть выполнить вставку только после того, как вы убедились, что ключ не существует, вы можете сделать это так:
map.entry("color").or_insert("red");
Это означает, что если нет ключа "color", добавьте его и установите значение "red", в противном случае пропустите.
Если уже известен ключ, и нужно напрямую изменить соответствующее значение, есть более быстрый способ:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert(1, "a"); if let Some(x) = map.get_mut(&1) { *x = "b"; {} {}