YouTip LogoYouTip

Rust Enum

Enums in Rust are not as simple as the concept in other programming languages, but they can still be used quite easily: ## Example #[derive(Debug)] enum Book { Papery, Electronic } fn main(){ let book = Book::Papery; println!("{:?}", book); } Output: Papery Books are divided into paper books (Papery book) and electronic books (Electronic book). If you are currently developing a library management system and need to describe the different attributes of two types of books (paper books have a call number, e-books only have a URL), you can add tuple attributes to the enum members: enum Book { Papery(u32), Electronic(String),}let book = Book::Papery(1001);let ebook = Book::Electronic(String::from("url://...")); If you want to name the attributes, you can use struct syntax: enum Book { Papery { index: u32 }, Electronic { url: String },}let book = Book::Papery{index: 1001}; Although you can name them this way, please note that you cannot access the attributes bound to the enum in the same way you access struct fields. The method for access is in the `match` syntax. ### `match` Syntax The purpose of an enum is to classify a certain type of thing, and the purpose of classification is to describe different situations. Based on this principle, enums are often ultimately handled by branching structures (similar to `switch` in many languages). The `switch` syntax is classic, but it is not supported in Rust. Many languages have abandoned `switch` because it easily leads to fall-through execution issues due to forgetting to add `break`. Languages like Java and C# prevent this situation through safety checks. Rust implements branching structures through the `match` statement. First, let's see how to use `match` to handle enums: ## Example 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); } } } Output: Papery book 1001 A `match` block can also be treated as a function expression; it can also have a return value: match enum_instance { pattern1 => return_expression, pattern2 => return_expression, ...} But the types of all return expressions must be the same! If you define the enum's additional attributes as tuples, you need to temporarily assign a name in the `match` block: ## Example enum Book { Papery(u32), Electronic {url: String}, } let book = Book::Papery(1001); match book { Book::Papery(i)=>{ println!("{}", i); }, Book::Electronic{ url }=>{ println!("{}", url); } } Besides branching on enums, `match` can also branch on integers, floating-point numbers, characters, and string slice references (`&str`) types. While branching on floating-point types is legal, it is not recommended because precision issues may lead to incorrect branches. When branching on non-enum types, you must pay attention to handling exceptional cases, even if there is nothing to do in the exceptional case. Exceptional cases are represented by an underscore `_`: ## Example fn main(){ let t ="abc"; match t { "abc"=> println!("Yes"), _ =>{}, } } * * * ## The `Option` Enum `Option` is an enum in the Rust standard library. This enum is used to fill the gap left by Rust's lack of support for null references. Many languages support the existence of null (C/C++, Java), which is convenient but also creates huge problems. The inventor of null also acknowledged this, "A billion-dollar mistake." Null often delivers a fatal blow to programs when developers assume everything is not null: after all, just one such error can cause the program to terminate completely. To solve this problem, many languages disallow null by default but support its existence at the language level (often denoted with a `?` symbol before the type). Java supports null by default but can restrict its appearance with the `@NotNull` annotation, which is a workaround. Rust completely disallows the existence of null at the language level. However, since null can efficiently solve a small number of problems, Rust introduced the `Option` enum: enum Option { Some(T), None,} If you want to define a class that can be null, you can do this: let opt = Option::Some("Hello"); If you want to perform some operation on `opt`, you must first check if it is **`Option::None`**: ## Example fn main(){ let opt =Option::Some("Hello"); match opt { Option::Some(something)=>{ println!("{}", something); }, Option::None=>{ println!("opt is nothing"); } } } Output: Hello If your variable starts as null, consider the compiler: how would it know the type of the variable when the value is not null? Therefore, an `Option` with an initial null value must have its type explicitly specified: ## Example fn main(){ let opt: Option<&str>=Option::None; match opt { Option::Some(something)=>{ println!("{}", something); }, Option::None=>{ println!("opt is nothing"); } } } Output: opt is nothing This design makes null programming less easy, but this is exactly what is needed to build a stable and efficient system. Since `Option` is imported by default by the Rust compiler, you can omit `Option::` and directly write `None` or `Some()` when using it. `Option` is a special enum that can contain values for branching: ## Example fn main(){ let t = Some(64); match t { Some(64)=> println!("Yes"), _ => println!("No"), } } ### `if let` Syntax ## Example let i =0; match i { 0=> println!("zero"), _ =>{}, } Running in the main function outputs: zero The purpose of this program is to check if `i` is the number 0, and if so, print "zero". Now use `if let` syntax to shorten this code: let i = 0;if let 0 = i { println!("zero");} The `if let` syntax format is as follows: if let pattern = source_variable { statement_block} You can add an `else` block afterward to handle exceptional cases. The `if let` syntax can be considered "syntactic sugar" for a `match` statement that only distinguishes between two cases (syntactic sugar refers to a convenient alternative with the same principle as a certain syntax). It still applies to enums: ## Example 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!("Not papery book"); } }
← Os GetcwdRust Slice β†’