Let制御フロー

Rust には、他の言語とは異なる制御フロー構造がいくつかあります。これらはパターン マッチングに使用されます。

  • if let
  • let else
  • while let

if let

if let を使用すると、値がパターンに一致するかどうかに応じて異なるコードを実行できます。

use std::time::Duration;

fn sleep_for(secs: f32) {
    if let Ok(duration) = Duration::try_from_secs_f32(secs) {
        std::thread::sleep(duration);
        println!("slept for {duration:?}");
    }
}

fn main() {
    sleep_for(-10.0);
    sleep_for(0.8);
}

let else

パターンをマッチして関数から戻るという一般的なケースでは、let else を使用します。「else」ケースは発散する必要があります(returnbreak、パニックなど、ブロックから抜けるもの以外のすべて)。

fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
    if let Some(s) = maybe_string {
        if let Some(first_byte_char) = s.chars().next() {
            if let Some(digit) = first_byte_char.to_digit(16) {
                Ok(digit)
            } else {
                return Err(String::from("not a hex digit"));
            }
        } else {
            return Err(String::from("got empty string"));
        }
    } else {
        return Err(String::from("got None"));
    }
}

fn main() {
    println!("result: {:?}", hex_or_die_trying(Some(String::from("foo"))));
}

if let に似た while let 派生物もあります。これは、パターンに照らして値をテストします。

fn main() {
    let mut name = String::from("Comprehensive Rust 🦀");
    while let Some(c) = name.pop() {
        println!("character: {c}");
    }
    // (There are more efficient ways to reverse a string!)
}

ここで String::pop は、文字列が空になるまで Some(c) を返し、その後 None を返します。while let を使用すると、すべてのアイテムに対して反復処理を続行できます。

This slide should take about 10 minutes.

if-let

  • match とは異なり、if let ではすべての分岐を網羅する必要はないため、match よりも簡潔になります。
  • 一般的な使用方法は、Option を操作するときに Some 値を処理することです。
  • match とは異なり、if let はパターン マッチングでガード節をサポートしていません。

let-else

次に示すように、if let は積み重なってしまうことがあります。let-else の構成は、このネストされたコードを平坦にする助けとなります。読みづらいバージョンを受講者向けに書き直して、受講者が変化を確認できるようにします。

書き換えたバージョンは次のとおりです。

#![allow(unused)]
fn main() {
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
    let Some(s) = maybe_string else {
        return Err(String::from("got None"));
    };

    let Some(first_byte_char) = s.chars().next() else {
        return Err(String::from("got empty string"));
    };

    let Some(digit) = first_byte_char.to_digit(16) else {
        return Err(String::from("not a hex digit"));
    };

    return Ok(digit);
}
}

while-let

  • 値がパターンに一致する限り、while let ループが繰り返されることを説明します。
  • name.pop() でunwrapする値がない場合に中断する if ステートメントを使用して、while let ループを無限ループに書き換えることができます。while let は、上記のシナリオの糖衣構文として使用できます。