English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
枚举类在 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 문법 내에 있습니다.
비례형의 목적은 특정 유형의 사물을 분류하는 것이며, 분류의 목적은 다른 상황을 설명하는 것입니다. 이 원리에 따라 비례형 클래스는 종종 분기 구조로 처리됩니다( 많은 언어에서 switch). switch 문법은 매우 전통적이지만, Rust에서는 지원되지 않으며, 많은 언어가 switch를 포기하는 이유는 switch가 break를 추가하지 않아서 발생할 수 있는 연속 실행 문제가 있기 때문입니다. Java와 C#과 같은 언어는 안전한 검사를 통해 이러한 문제를 방지합니다.
Rust는 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) 타입의 데이터에 대한 분기 선택도 할 수 있습니다. 실수 타입은 분기 선택이 가능하지만, 정확도 문제로 분기 오류가 발생할 수 있으므로 이렇게 사용하는 것은 권장되지 않습니다.
비례형 클래스에 대한 분기 선택을 할 때는 예외 상황을 처리해야 합니다. 예외 상황은 밑줄 _로 표시됩니다:
fn main() {
let t = "abc";
match t {
"abc" => println!("Yes"),
_ => {},
}
}
Option은 Rust 표준 라이브러리의 열거형 클래스로, 이 클래스는 Rust가 null 참조를 지원하지 않는 공백을 채우기 위해 사용됩니다.
많은 언어가 null의 존재를 지원합니다(C/C++、Java),이렇게 편리하지만, 동시에 매우 큰 문제를 만들어냅니다. null의 발명자도 이를 인정합니다. "편리한 아이디어는 누적된 문제를 만들어냅니다. 10 억의 손실".
null은 개발자가 모든 것을 null이 아닌 것으로 간주할 때 프로그램에 치명적인 타격을 줄 수 있습니다. 결국, 이러한 오류가 발생하면 프로그램의 실행이 완전히 중단됩니다.
이 문제를 해결하기 위해 많은 언어는 기본적으로 null을 허용하지만, 언어 수준에서 null의 발생을 지원합니다(보통 타입 앞에 ? 기호를 사용하여 표시).
Java는 기본적으로 null을 지원하지만, @NotNull 애노테이션을 통해 null의 발생을 제한할 수 있습니다. 이는 대체적인 방법입니다.
Rust는 언어 수준에서 null 값의 존재를 완전히 금지하지만, 불가피하게 null은 일부 문제를 효율적으로 해결할 수 있기 때문에 Rust는 Option 열거형 클래스를 도입했습니다:
enum Option<T> { Some(T), None, }
如果你想定义一个可以为空值的类,你可以这样:
let opt = Option::Some("Hello");
如果你想针对 opt를 수행할 일정한 작업을 수행하려면, 먼저 그것이 무엇인지�断해야 합니다 Option::None:
fn main() {
let opt = Option::Some("Hello");
match opt {
Option::Some(something) => {
println!("{}", something);
},
Option::None => {
println!("opt는 아무것도 아닙니다");
}
}
}
실행 결과:
Hello
如果你的变量刚开始是空值,你体谅一下编译器,它怎么知道值不为空的时候变量是什么类型的呢?
따라서 비어 있는 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"),
}
}
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);
} else {
println!("Not papery book");
}
}