کنترل جریان Let

زبان Rust چند ساختار کنترل جریان دارد که با سایر زبان‌ها متفاوت است. این ساختارها برای مطابقت الگو استفاده می‌شوند:

  • عبارت if let
  • عبارت let else
  • عبارت while let

عبارت if let

عبارت if let به شما امکان می‌دهد بسته به اینکه آیا یک مقدار با یک الگو مطابقت دارد، کدهای مختلفی را اجرا کنید:

use std::time::Duration;

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

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

عبارت let else

برای حالت رایج مطابقت با یک الگو و بازگشت از تابع، از let else استفاده کنید. در اینجا، حالت "else" باید منحرف شود (مانند return، break، یا panic - به غیر از اینکه از انتهای بلوک خارج شود).

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("نه یک hex digit"));
            }
        } else {
            return Err(String::from("یک string خالی دریافت کردم"));
        }
    } else {
        return Err(String::from("هیچ‌کدام"));
    }
}

fn main() {
    println!("نتیجه: {:?}", 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 استفاده کنید.
  • یک استفاده رایج از دستور if let، رسیدگی به مقادیر Some هنگام کار با Option است.
  • برخلاف دستور 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("هیچ‌کدام"));
    };

    let Some(first_byte_char) = s.chars().next() else {
        return Err(String::from("یک string خالی دریافت کردم"));
    };

    let Some(digit) = first_byte_char.to_digit(16) else {
        return Err(String::from("نه یک hex digit"));
    };

    return Ok(digit);
}
}

while-let

  • توجه داشته باشید که حلقه while let تا زمانی که مقادیر مقابل الگو طبیق داشته باشد (شرط برقرار باشد)، ادامه خواهد داشت.
  • شما می‌توانید حلقه‌ی while let را به صورت یک حلقه بی‌پایان با یک دستور if بازنویسی کنید که در صورت عدم وجود مقداری برای باز کردن (unwrap) از ()name.pop، شکسته می‌شود. while let یک Syntactic sugar برای این سناریو ارائه می‌دهد.