🦀

The Rust Programing Language 4日目

2023/11/03に公開

前回のあらすじ
構造体については割とすんなり受け入れられたのであった。
今日は6章

Enumとパターンマッチング

本日の学び

Enum

  • 複数の値を取り得る、かつ同様の型として扱いたい際に有用である
    • 色んな種類があるけど状態が重なることがないもの
    • 例ではIPv4とIPv6
    enum IpAddrKind {
        V4,
        V6,
    }
    
    • IpAddrKind::v4の様に初期化できる
    • v4でもv6でもIpAddrKind型なので、関数を定義しやすい
  • 値を紐づけられる
    enum IpAddr {
        V4(String),
        V6(String),
    }
    
    let home = IpAddr::V4(String::from("127.0.0.1"));
    
    let loopback = IpAddr::V6(String::from("::1"));
    
    • 紐づける値の型はバラバラでも良い
  • 標準ライブラリ内にEnum定義がある
    • IPアドレスの定義はこれ
    • よく使いそうなものを用意してくれてるのは嬉しい
    • Javaにもこういうのあるのかな、気にしたことなかった
  • 別々の構造体作っても似た様な感じにはなる
    • 有利なのは、全てを引数に取れる関数を簡単に定義できること
  • Enumにもメソッドを定義できる

Option enum

  • これもまた標準ライブラリに定義されているenum
  • 値が何かか、そうでないかという概念を表す
  • Rustにはnullが無い
    • これ嬉しすぎる
  • nullが無いので、値が存在するか不在かというのをenumでコード化する
enum Option<T> {
    Some(T),
    None,
}
  • Option<T>は有益すぎるので、初期化処理にも含まれている
    • 明示的に追加せずいつでも使える
    • 列挙子もそうなっているので、Option::と書かずに使える
let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;
  • Option型の値とi8などを足し合わせたりすることはできない
    • Option<T>Tに変換しなくてはいけない

match

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

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        },
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
  • 基本的にはswitchみたいなものだと思う
  • enumと組み合わせると相性がいい
    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);
    
    • Some(i)Some(5)にmatchし、iに5が束縛される
    • これ意味はわかるけど、慣れるまで理解に時間がかかりそう

プレースホルダー(_)

  • matchは、取り得る全ての可能性を網羅しないとコンパイルエラーになる
    • Someのみ見てNoneを見ない場合など
    • u8を肩に取ったら、0〜255を列挙することになる
  • _というプレースホルダーは、あらゆるパターンにmatchする
    • 最後にこれの判定を入れておけば、考慮漏れは起きない
    • defaultだね

if let

  • 1つのパターンにmatchする場合のみ考える
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");
}
  • 網羅性は失われるが、シンプルな記述になる
  • elseを書くこともできる
    • _を書いた時と同じ動きになる

本日のまとめ

enum、正直クリティカルな使い方をあまりよくわかっていない状態で使ってたので、もっと使ってあげようと思った
matchは実際かなり使うのだろうか、便利そうな気もするのでAPI開発とかで体感したい
基礎文法だいぶわかってきた感じがあるが、あんまり自分で書いてないので読めばわかるけど書けないみたいになってそう
まあ体に覚えさすのは理解してからでもいいかな

明日は7章、パッケージやクレートの話題

Discussion