English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Списки Rust

В Rust энум-классы не так просты, как в других языках программирования, но их все же можно использовать очень просто:

#[derive(Debug)]

enum Book {
    Papery, Electronic
{}

fn main() {
    let book = Book::Papery;
    println!("{:?}", book);
{}

Результат выполнения:

Papery

Книги делятся на бумажные книги (Papery book) и электронные книги (Electronic book).

Если вы сейчас разрабатываете систему управления библиотекой, вам нужно описать различные атрибуты двух типов книг (бумажные книги имеют индекс книги, электронные книги имеют только URL), вы можете добавить описание свойств векторных членов枚举-класса:

enum Book {
    Papery(u32),
    Electronic(String),
{}
let book = Book::Papery(1001);
let ebook = Book::Electronic(String::from("url://..."));

Если вы хотите命名 атрибут, вы можете использовать синтаксис структуры:

enum Book {
    Papery { index: u32 },
    Electronic { url: String },
{}
let book = Book::Papery{index: 1001};

Хотя можно так называть, но请注意,并不能像访问结构体字段一样访问枚举类绑定的属性。访问的方法在 match 语法中。

грамматика match

Цель枚герации - классификация определенного класса вещей, цель классификации - описание различных ситуаций. На основе этого принципа, перечисляемые классы часто обрабатываются с помощью структуры ветвления (как switch в многих языках). Грамматика switch очень классическая, но в Rust она не поддерживается, многие языки отказались от switch из-за проблем, связанных с chaining, которые могут возникнуть, если забыть добавить break, Java и C# используют безопасные проверки, чтобы предотвратить这种情况.

Rust реализует структуру ветвления с помощью оператора match. Давайте сначала рассмотрим, как использовать match для обработки перечисляемых классов:

fn main() {
    enum Book {
        Papery {index: u32},
        Electronic {url: String},
    {}
   
    let book = Book::Papery{index: 1001};
    let ebook = Book::Electronic{url: String::from("url...")};
   
    match book {
        Book::Papery { index } => {
            println!("Papery book {}", index);
        },
        Book::Electronic { url } => {
            println!("E-book {}", url);
        {}
    {}
{}

Результат выполнения:

Papery book 1001

Блок match также может рассматриваться как функциональное выражение, у него также может быть возвращаемое значение:

match пример перечисляемого класса {
    Категория 1 => выражение возвращаемого значения,
    Категория 2 => выражение возвращаемого значения,
    ...
{}

Но тип всех выражений возвращаемых значений должен быть одинаков!

Если атрибуты перечисляемого класса определены в виде кортежа, в блоке match необходимо временно указать имя:

enum Book {
    Papery(u32),
    Electronic {url: String},
{}
let book = Book::Papery(1001);

match book {
    Book::Papery(i) => {
        println!("{}", i);
    },
    Book::Electronic { url } => {
        println!("{}", url);
    {}
{}

match, кроме того, что позволяет выбирать ветвление для перечисляемых классов, также может выбирать ветвление для данных типа целое число,浮点ное число, символ и строковый срез (&str). Хотя использование ветвления для типа float является законным, его не рекомендуется использовать, так как проблемы с точностью могут привести к ошибкам в ветвлении.

При выборе ветвления для не перечисляемых классов необходимо учитывать обработку исключительных ситуаций, даже если в исключительных ситуациях нет действий, которые нужно выполнить. Исключительные ситуации обозначаются подчеркиванием _:

fn main() {
    let t = "abc";
    match t {
        "abc" => println!("Да"),
        _ => {},
    {}
{}

枚举类 Option

Option - это枚ративный класс из стандартной библиотеки Rust, который используется для заполнения пробела в Rust,不支持 null-ссылки.

Многие языки поддерживают существование null (C/C++, Java), что очень удобно, но также создает огромные проблемы, null был создан, и его создатели признают это: "простая идея привела к потере 10 миллиардов долларов".

Null часто наносит смертельный удар программе, когда разработчики считают, что всё не null:毕竟, один такой ошибочный случай может привести к полному прекращению работы программы.

Чтобы решить эту проблему, многие языки по умолчанию не позволяют null, но поддерживают его的出现 на уровне языка (часто обозначается символом ? перед типом).

Java по умолчанию поддерживает null, но можно ограничить его的出现 с помощью аннотации @NotNull, это один из способов справиться с этим.

Rust полностью не допускает的存在 пустого значения null на уровне языка, но, к сожалению, null может эффективно решать少量 проблем, поэтому Rust ввел枚ративный класс Option:

enum Option<T> {
    Some(T),
    None,
{}

Если вы хотите определить класс, который может быть пустым, вы можете сделать это так:

let opt = Option::Some("Привет");

Если вы хотите выполнить某些 действия с opt, вы должны сначала�断, является ли он Option::None:

fn main() {
    let opt = Option::Some("Привет");
    match opt {
        Option::Some(something) => {
            println!("{}", something);
        },
        Option::None => {
            println!("opt не что иное");
        {}
    {}
{}

Результат выполнения:

Привет

Если переменная в начале空的, проявите понимание к компилятору: как он может знать, что переменная не пуста, если он не знает её типа?

Таким образом, пустой Option должен иметь明确规定 типа:

fn main() {
    let opt: Option<&str> = Option::None;
    match opt {
        Option::Some(something) => {
            println!("{}", something);
        },
        Option::None => {
            println!("opt не что иное");
        {}
    {}
{}

Результат выполнения:

opt не что иное

Этот дизайн делает сложнее программирование с пустыми значениями, но это именно то, что нужно для создания стабильной и эффективной системы. Поскольку Option по умолчанию вводится компилятором Rust, при использовании можно опускать Option:: и напрямую писать None или Some().

Option - это особый список, который может выбирать между ветвями значений:

fn main() {
        let t = Some(64);
        match t {
                Some(64) => println!("Yes"),
                _ => println!("No"),
        {}
{}

Грамматика if let

let i = 0;
match i {
    0 => println!("zero"),
    _ => {},
{}

Вывод в главную функцию программы:

zero

Цель этого программы - определить, является ли i числом 0, и если да, то напечатать zero.

Теперь укорачиваем этот фрагмент кода с помощью грамматики if let:

let i = 0;
if let 0 = i {
    println!("zero");
{}

Формат грамматики if let:

if let значение = переменная_источника {
    Блок инструкций
{}

После этого можно добавить блок else для обработки исключительных случаев.

Грамматика if let можно рассматривать как "сладкую пасту" для match-выражений, которые различают только два случая (сладкая паста - это удобный заменитель, имеющий те же принципы грамматики).

Для списков также применяется:

fn main() {
    enum Book {
        Papery(u32),
        Electronic(String)
    {}
    let book = Book::Electronic(String::from("url"));
    if let Book::Papery(index) = book {
        println!("Papery {}", index);
    }
        println!("Not papery book");
    {}
{}