zoukankan      html  css  js  c++  java
  • 2.8 枚举与模式匹配

    Enums and Pattern Matching

    Defining an Enum

    枚举属性的类型统一为枚举的名称

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

    Note that the variants of the enum are namespaced under its identifier, and we use a double colon to separate the two. The reason this is useful is that now both values IpAddrKind::V4 and IpAddrKind::V6 are of the same type: IpAddrKind. We can then, for instance, define a function that takes any IpAddrKind:

    fn route(ip_kind: IpAddrKind) {}
    route(IpAddrKind::V4);
    route(IpAddrKind::V6);
        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 IpAddr {
            V4(String),
            V6(String),
        }
    
        let home = IpAddr::V4(String::from("127.0.0.1"));
    
        let loopback = IpAddr::V6(String::from("::1"));
    fn main() {
        enum IpAddr {
            V4(u8, u8, u8, u8),
            V6(String),
        }
    
        let home = IpAddr::V4(127, 0, 0, 1);
    
        let loopback = IpAddr::V6(String::from("::1"));
    }
    #![allow(unused_variables)]
    fn main() {
    struct Ipv4Addr {
        // --snip--
    }
    
    struct Ipv6Addr {
        // --snip--
    }
    
    enum IpAddr {
        V4(Ipv4Addr),
        V6(Ipv6Addr),
    }
    }
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    This enum has four variants with different types:

    • Quit has no data associated with it at all.
    • Move includes an anonymous struct inside it.
    • Write includes a single String.
    • ChangeColor includes three i32 values.
    fn main() {
        enum Message {
            Quit,
            Move { x: i32, y: i32 },
            Write(String),
            ChangeColor(i32, i32, i32),
        }
    
        impl Message {
            fn call(&self) {
                // method body would be defined here
            }
        }
    
        let m = Message::Write(String::from("hello"));
        m.call();
    }

    [derive(Debug)] 会自动实现一个输出格式,然后就可以使用{:?}输出枚举

    fn testEnum(){
    
        #[derive(Debug)]
        enum Message {
            Quit,
            Move{x: i16, y: i16},
            Write(String),
            ChangeColor(i32,i32,i32),
        }
    
        impl Message {
            fn call(&self) {
                let v1 = Message::Quit;
                let v2 = Message::Move{x: 25, y: 25};
                
                let v4 = Message::ChangeColor(100,100,100);
                println!("{:#?} ",v1);
                println!("{:#?} ",v2);
                println!("{:?}",v4);
            }
    
    
        }
    
        let m = Message::Write(String::from("enum show "));
        println!("{:?}",m);
        m.call();
    }
    Write("enum show ")
    Quit 
    Move {
        x: 25,
        y: 25,
    } 
    ChangeColor(100, 100, 100)

    The Option Enum and Its Advantages Over Null Values

    Programming language design is often thought of in terms of which features you include, but the features you exclude are important too. Rust doesn’t have the null feature that many other languages have. Null is a value that means there is no value there. In languages with null, variables can always be in one of two states: null or not-null.

    The problem isn’t really with the concept but with the particular implementation. As such, Rust does not have nulls, but it does have an enum that can encode the concept of a value being present or absent. This enum is Option<T>, and it is defined by the standard library as follows:

    #![allow(unused_variables)]
    fn main() {
    enum Option<T> {
        Some(T),
        None,
    }
    }

    The Option<T> enum is so useful that it’s even included in the prelude; you don’t need to bring it into scope explicitly. In addition, so are its variants: you can use Some and None directly without the Option:: prefix. The Option<T> enum is still just a regular enum, and Some(T) and None are still variants of type Option<T>.

    The <T> syntax is a feature of Rust we haven’t talked about yet. It’s a generic type parameter, and we’ll cover generics in more detail in Chapter 10. For now, all you need to know is that <T> means the Some variant of the Option enum can hold one piece of data of any type. Here are some examples of using Option values to hold number types and string types:

    fn main() {
        let some_number = Some(5);
        let some_string = Some("a string");
    
        let absent_number: Option<i32> = None;
    }

    In short, because Option<T> and T (where T can be any type) are different types, the compiler won’t let us use an Option<T> value as if it were definitely a valid value. For example, this code won’t compile because it’s trying to add an i8 to an Option<i8>:

    fn main() {
        let x: i8 = 5;
        let y: Option<i8> = Some(5);
    
        let sum = x + y;//error
    }

    The match Control Flow Operator

    Rust has an extremely powerful control flow operator called match that allows you to compare a value against a series of patterns and then execute code based on which pattern matches. Patterns can be made up of literal values, variable names, wildcards, and many other things;
    fn main() {
        println!("----------match----------");
        let coin = Coin::Penny;
        let res = value_in_cents(coin);
        println!("{}",res);
    
        let coin = Coin::Dime;
        let res = value_in_cents(coin);
        println!("{}",res);
    }
    
    
    enum Coin {
        Penny,
        Nockel,
        Dime,
        Quarter,
    }
    
    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nockel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }
    $ cargo run
       Compiling enum_match v0.1.0 (/opt/wks/rust_study/enum_match)
    warning: variant is never constructed: `Nockel`
      --> src/main.rs:15:5
       |
    15 |     Nockel,
       |     ^^^^^^
       |
       = note: `#[warn(dead_code)]` on by default
    
    warning: variant is never constructed: `Quarter`
      --> src/main.rs:17:5
       |
    17 |     Quarter,
       |     ^^^^^^^
    
    warning: 2 warnings emitted
    
        Finished dev [unoptimized + debuginfo] target(s) in 0.52s
         Running `target/debug/enum_match`
    ----------match----------
    1
    10
    #[derive(Debug)]
    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
            }
        }
    }
    
    fn main() {
        value_in_cents(Coin::Quarter(UsState::Alaska));
    }
    Option<T> match
    #[derive(Debug)]
    enum Option<T> {
        None,
        Some(T)
    }
    
    fn plus_one(x: Option<i32>) -> Option<i32>{
        match x {
            Option::None => Option::None,
            Option::Some(i) => Option::Some(i+1),
        }
    }
    
    fn test_match(){
        let five = Option::Some(5);
        let six = plus_one(five);
        println!("{:?}",six);
        let none = plus_one(Option::None);
        println!("{:?}",none);
    }

    Matches Are Exhaustive

    fn main() {
        fn plus_one(x: Option<i32>) -> Option<i32> {
            match x {
                Some(i) => Some(i + 1),
            }
        }
    
        let five = Some(5);
        let six = plus_one(five);
        let none = plus_one(None);
    }

    We didn’t handle the None case, so this code will cause a bug. Luckily, it’s a bug Rust knows how to catch. If we try to compile this code, we’ll get this error:

    $ 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
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0004`.
    error: could not compile `enums`.
    
    To learn more, run the command again with --verbose.

    The _ Placeholder

    Rust also has a pattern we can use when we don’t want to list all possible values. For example, a u8 can have valid values of 0 through 255. If we only care about the values 1, 3, 5, and 7, we don’t want to have to list out 0, 2, 4, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can use the special pattern _ instead:

    fn main() {
        let some_u8_value = 0u8;
        match some_u8_value {
            1 => println!("one"),
            3 => println!("three"),
            5 => println!("five"),
            7 => println!("seven"),
            _ => (),
        }
    }
    _ => (),
    这一行表示轮空,什么也不会输出

    The _ pattern will match any value. By putting it after our other arms, the _ will match all the possible cases that aren’t specified before it. The () is just the unit value, so nothing will happen in the _ case. As a result, we can say that we want to do nothing for all the possible values that we don’t list before the _ placeholder.

    However, the match expression can be a bit wordy in a situation in which we care about only one of the cases. For this situation, Rust provides if let.

    Concise Control flow with if let

    #![allow(unused_variables)]
    fn main() {
        println!("Hello, match!");
        let1();
        let2();
    }
    
    #[derive(Debug)]
    enum Option<T> {
        Some(T),
        None
    }
    
    
    fn let1(){
        let some_u3_value = Option::Some(0u8);
        match some_u3_value {
            Option::Some(3) => println!("three"),
            _ => (),
        }
    
        if let Option::Some(3) = some_u3_value{
            println!("three");
        }
    
    }
    
    fn let2(){
        let some_u3_value = Option::Some(0u8);
        let mut count = 0;
        match some_u3_value {
            Option::Some(3) => println!("three"),
            _ => count += 1,
        }
    
        if let Option::Some(3) = some_u3_value{
            println!("three");
        }else{
            count += 1;
        }
        println!("{}",count);
    }
  • 相关阅读:
    ML-线性回归
    ML-决策树
    numpy常用知识点备忘(2)
    numpy常用知识点备忘
    ML-朴素贝叶斯算法
    Git常用命令备忘
    机器学习-决策树算法
    机器学习-线性模型(线性回归与逻辑回归)
    深入JVM内核(四)垃圾回收器与GC参数
    深入JVM内核(三)对象存活判定算法与垃圾收集算法
  • 原文地址:https://www.cnblogs.com/perfei/p/13071917.html
Copyright © 2011-2022 走看看