ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

RUST 0x05 Enum

2019-11-09 17:00:57  阅读:298  来源: 互联网

标签:Enum Option 0x05 IpAddrKind enum Some let Coin RUST


RUST 0x05 Enum

1 定义一个Enum

如:

enum IpAddrKind {
    V4,
    V6,
}

enum的值只能是它的变量中的一个。

Enum Values

可以像这样创建实例:

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

enum里的变量是在其namespace下的,所以要用::。这时IpAddrKind::V4IpAddrKind::V6是同一种类型——IpAddrKind,所以可以像这样:

fn route(ip_kind: IpAddrKind) { 
route(IpAddrKind::V4);
route(IpAddrKind::V6);

可以这样将enum和struct组合使用:

enum IpAddrKind {
    V4,
    V6,
}

struct IpAddr {
    kind: IpAddrKind,
    address: String,
}

let home = IpAddr {
    kind: IpAddrKind::V4,
    address: String::from("127.0.0.1"),
};

let loopback = IpAddr {
    kind: IpAddrKind::V6,
    address: String::from("::1"),
};

也可以直接在enum里使V4V6变量与String值相联系:

enum IpAddr {
    V4(String),
    V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));

let loopback = IpAddr::V6(String::from("::1"));

enum比struct的一个优越之处在于:每一个变量都可以拥有不同类型的、不同数量的相关数据,比如:

enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);

let loopback = IpAddr::V6(String::from("::1"));

除了string、数字类型,我们当然也可以在enum里放struct甚至另一个enum,比如:

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

这个enum中含有四个不同类型的变量:

  • Quit没有相关数据。
  • Move中有一个anonymous struct。
  • Wtite中有一个String
  • ChangeColor中有三个i32

与struct类似,enum也可以在impl中定义一些method,如:

impl Message {
    fn call(&self) {
        // method body would be defined here
    }
}

let m = Message::Write(String::from("hello"));
m.call();

Option Enum与它相比于Null Values的优势

Rust中没有Null Values,但是它有一种enum,可以encode变量现在present或absent的概念,如:

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

Option<T> enum仍然是一种regular enum,Some(T)None仍然是Option<T>类型的变量,但是如果要使用它们,可以直接使用,无需加Option::前缀。

  • <T>代表的是泛型(generic type),这意味着Some可以存储任何类型的数据。
let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;

如果我们要使用的不是Some而是None,我们需要告诉Rust Option<T>的类型,否则编译器就不知道Some应该存储的数据类型。

那么Option到底哪里比Null Value好了呢?——编译器不会让我们像使用一个绝对有效值一样使用一个Option<T>值。如下面的代码将会抛出一个CE,因为它试图把一个i8加到一个Option<i8>上:

let x: i8 = 5;
let y: Option<i8> = Some(5);

let sum = x + y;

也就是说,如果我们需要进行T能进行的操作,我们需要先把Option<T>转变为T。这样就可以防止一种错误:误以为某一个是null的值不是null。

2 The match Control Flow Operator

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        },
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
  • => → separates the pattern and the code to run.

注意一下这里用的仍然是,

Patterns that Bind to Values

enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        },
    }
}

当我们传递了一个 Coin::Quarter(UsState::Alaska) 时,UsState::Alaska会被绑定(bind)到state上。

Matching with Option<T>

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);

Matches Are Exhaustive

在match的时候,必须将enum中每一个变量对应的情况都写出来,尤其是在Option<T>的情况下。

The _ Placeholder

如果我们不想把所有可能的值都列出来,我们可以用_,比如:

let some_u8_value = 0u8;
match some_u8_value {
    1 => println!("one"),
    3 => println!("three"),
    5 => println!("five"),
    7 => println!("seven"),
    _ => (),
}

u8可以有0~255之间的值)。

3 Concise Control Flow with if let

如果要实现这样的功能:

let some_u8_value = Some(0u8);
match some_u8_value {
    Some(3) => println!("three"),
    _ => (),
}

我们可以用if let来减少码量:

if let Some(3) = some_u8_value {
    println!("three");
}

if let的工作原理和match一样,但是码量更少。

if let可以像if一样地加else,比如要实现这样的功能:

let mut count = 0;
match coin {
    Coin::Quarter(state) => println!("State quarter from {:?}!", state),
    _ => count += 1,
}

可以这样写:

let mut count = 0;
if let Coin::Quarter(state) = coin {
    println!("State quarter from {:?}!", state);
} else {
    count += 1;
}

小结

  • enum是一个enumerated values的集合。
  • Option<T>可以用来防止错误。
  • 如果想要获得enum内的值,可以用matchif let

参考

The Rust Programming Language by Steve Klabnik and Carol Nichols, with contributions from the Rust Community : https://doc.rust-lang.org/book/

标签:Enum,Option,0x05,IpAddrKind,enum,Some,let,Coin,RUST
来源: https://www.cnblogs.com/wr786/p/11826747.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有