Rust语言:枚举与match表达式

枚举在Rust里是很重要的一种类型,因为它体现了Rust的一个重要设计:必须处理空值和错误。

先看普通的枚举

enum IpAddrKind {
    V4,
    V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

这里的V4和V6称为IpAddrKind的变体。

C的枚举实际上是整型,但前面说过Rust是强类型语言,类型互转是很困难的。

每个enum变体都可以选择绑定一个数据,这个设计有什么用呢?

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

内置的Option枚举

enum Option {
    Some(T),
    None,
}

Option表示的是,可能有值也可能没有值的情况,如果有值,这个值在Some里,如果没有值,那就是None

十亿美元的错误

In his 2009 presentation “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of null, has this to say:

I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language.

My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

如果一个表达式返回了Option类型,要想从里面获取结果,就必须要处理空值情况,否则编译器就会报错。

fn plus_one(x: Option) -> Option {
    match x {
        Some(i) => Some(i + 1),
    }
}
$ cargo run
   Compiling enums v0.1.0 (file:///projects/enums)
error[E0004]: non-exhaustive patterns: `None` not covered
   --> src/main.rs:3:15
    |
3   |         match x {
    |               ^ pattern `None` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `Option`

error: aborting due to previous error

内置的Result枚举

Result用于返回一个结果,但也有可能出错的情况,使用枚举,就要求调用方要显式地处理错误。

enum Result {
    Ok(T),
    Err(E),
}

比如打开一个文件

use std::fs::File;

fn main() {
    let f: u32 = File::open("hello.txt");
}

可是没有输出令人兴奋的结果

$ cargo run
   Compiling error-handling v0.1.0 (file:///projects/error-handling)
error[E0308]: mismatched types
 --> src/main.rs:4:18
  |
4 |     let f: u32 = File::open("hello.txt");
  |            ---   ^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found enum `std::result::Result`
  |            |
  |            expected due to this
  |
  = note: expected type `u32`
             found enum `std::result::Result`

因为类型不对。

标准库返回的是Result类型,必须显式地处理成功和错误两种情况。

Rust的难学之一体现在不断地与编译器博斗使代码编译通过,这也是可以理解的。

因为Rust把很多在运行时检查的内容提前到了编译阶段,而当编译器不能推断出确定的规则时,只能要求编码者提供更具体的信息,以帮助编译器判断代码的问题。

用Rust的感觉就像侍奉编译器的感觉。也由于这个原因,Rust的编译速度相对较慢。

尽管如此,这仍然是Rust让人兴奋的一个地方,因为定位一个运行中程序bug的成本要远高于成功编译一个健康的程序,更多的时候,我们希望编译器能做得更多,而不是更少。

展开阅读全文

页面更新:2024-03-14

标签:表达式   变体   编译器   错误   类型   语言   感觉   情况   代码   程序   更多

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top