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

Classe Enum do Rust

A classe enum no Rust não é tão simples quanto em outros idiomas de programação, mas ainda pode ser usada de maneira muito simples:

#[derive(Debug)]

enum Book {
    Papery, Electrônico
}

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

Resultado da execução:

Papery

Os livros são divididos em livros impressos (livro Papery) e livros eletrônicos (livro Electrônico).

Se você estiver desenvolvendo um sistema de gerenciamento de livros agora, você precisa descrever os diferentes atributos de dois tipos de livros (os livros impressos têm o número de chamada e os livros eletrônicos têm apenas URL), você pode adicionar atributos de tupla descritivos aos membros da classe enum:

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

Se você quiser nomear um atributo, pode usar a sintaxe de estrutura:

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

Although it can be named like this, please note that enum class bound properties cannot be accessed like structure fields. The method of accessing them is in the match syntax.

match syntax

The purpose of enums is to classify a certain type of thing, and the purpose of classification is to describe different situations. Based on this principle, enum types are often handled by branch structures (similar to switch in many languages). The switch syntax is classic, but it is not supported in Rust. Many languages abandon switch because switch is prone to chaining execution problems due to forgetting to add break, and languages like Java and C# eliminate this situation through safety checks.

Rust implements branch structures through match statements. First, let's get to know how to use match to handle enum types:

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);
        }
    }
}

Running result:

Papery book 1001

The match block can also be treated as a function expression and can also have a return value:

match enum class example {
    Classification1 => return value expression,
    Classification2 => return value expression,
    ...
}

However, all return value expression types must be the same!

If the attached properties of an enum type are defined as tuples, a temporary name must be specified in the match block:

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

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

In addition to being able to make branch selections for enum types, match can also make branch selections for integer, floating-point, character, and string slice reference (&str) types of data. Although it is legal to make branch selections for floating-point types, it is not recommended to do so because precision issues may lead to branch errors.

When making branch selections for non-enum types, it is necessary to handle exceptions, even if there is nothing to do in the exception case. Exceptions are indicated by an underscore _:

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

Classe de enumeração Option

Option é uma classe de enumeração da biblioteca padrão do Rust, esta classe é usada para preencher a lacuna de referência null não suportada pelo Rust.

Muitos idiomas suportam a existência de null (C/C++、Java),o que é conveniente, mas também cria muitos problemas, o inventor do null também reconhece isso, "uma ideia conveniente causou uma acumulação 10 de perdas em bilhões de dólares".

null frequentemente dá um golpe mortal ao programa quando o desenvolvedor assume que tudo não é null: afinal, com um erro desses, a execução do programa deve ser completamente interrompida.

Para resolver este problema, muitos idiomas não permitem null por padrão, mas suportam a ocorrência de null no nível da linguagem (comumente marcado com o símbolo ? no tipo).

O Java suporta null por padrão, mas pode ser limitado pelo anotação @NotNull, o que é uma solução improvisada.

O Rust não permite a existência de valores nulos null em todos os níveis da linguagem, mas infelizmente null pode resolver alguns problemas de forma eficiente, então o Rust introduziu a classe de enumeração Option:

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

Se você quiser definir uma classe que pode ser nula, você pode fazer assim:

let opt = Option::Some("Olá");

Se você quiser executar algumas operações no opt, você deve primeiro determinar se ele é Option::None:

fn main() {
    let opt = Option::Some40;"Olá");
    match opt123;
        Option::Some40;algo) => {
            println!("{}", algo);
        },
        Option::None => {
            println!("opt não é nada");
        }
    }
}

Resultado da execução:

Olá

Se o seu variável começar como um valor nulo, tenha compaixão pelo compilador, como ele saberá o tipo da variável quando o valor não for nulo?

Portanto, a Option inicialmente vazia deve especificar o tipo explicitamente:

fn main() {
    let opt: Option<&str> = Option::None;
    match opt123;
        Option::Some40;algo) => {
            println!("{}", algo);
        },
        Option::None => {
            println!("opt não é nada");
        }
    }
}

Resultado da execução:

opt não é nada

Este design tornará a programação de valores nulos mais difícil, mas isso é exatamente o que é necessário para construir um sistema estável e eficiente. Devido ao Option ser introduzido pelo compilador Rust por padrão, ele pode ser omitido ao usar Option:: e pode ser escrito diretamente None ou Some().

Option é uma classe especial de enumeração, que pode conter ramificações de valor de escolha:

fn main() {
        let t = Some(64);
        match t {
                Some(64) => println!("Sim"),
                _ => println!("Não"),
        }
}

Sintaxe if let

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

Coloque-o na execução do main e veja os resultados:

zero

O objetivo deste programa é determinar se i é o número 0 e, se for, imprimir zero.

Agora use a sintaxe if let para abreviar este código:

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

A sintaxe do if let é a seguinte:

if let valor_de_match = variável_de_origem {
    Bloco de Comando
}

Pode-se adicionar um bloco else para lidar com casos excepcionais mais tarde.

A sintaxe if let pode ser considerada uma "dextrose" (substituto conveniente com o mesmo princípio de sintaxe) de uma declaração match que distingue apenas duas situações.

A sintaxe if let também se aplica às classes enum:

fn main() {
    enum Book {
        Papery(u32),
        Electronic(String)
    }
    let book = Book::Electronic(String::from("url"));
    if let Book::Papery(index) = book {
        println!("Papery {}", index);
    } else {
        println!("Não é um livro de papel");
    }
}