Rust: المطابقة المتقدمة للأنماط في لغة Rust

آخر تحديث: 2026-08-26

تُعد مطابقة الأنماط إحدى أقوى ميزات لغة Rust، وتتيح لك التقنيات المتقدمة مثل match الحراس، و@ الارتباطات، والأنماط المتعددة، ممارسة تحكم أكثر دقة في عمليات المطابقة — ليس فقط «مطابقة القيم»، بل «مطابقة الشروط».

إذا كانت مطابقة الأنماط الأساسية تشبه السؤال متعدد الخيارات (اختيار فرع واحد لتنفيذه)، فإن مطابقة الأنماط المتقدمة تشبه السؤال المركب — حيث يمكنك التحقق من القيم، وربط المراجع، وتقييم الشروط الإضافية، كل ذلك في الوقت نفسه.


1. ما ستتعلمه



2. قصة عن تقييم أداء الموظف

(1) التحدي: استخدام سلسلة من عبارات «if-else» للحصول على تقييم شامل

توم هو مدير الموارد البشرية في الشركة، ويحتاج إلى إعطاء تقييمات شاملة استنادًا إلى درجات الأداء وسجلات الحضور للموظفين.

القواعد هي كما يلي:

المستوى درجة الأداء شروط الحضور
A+ ≥95 حضور كامل (≥22 يومًا)
أ ≥85 الحضور ≥ 20 يومًا
ب ≥70 الحضور ≥ 18 يومًا
C ≥60
D <60

في البداية، كتب سلسلة طويلة من if-else:

RUST
fn rate_employee(score: u32, attendance: u32) -> &'static str {
    if score >= 95 && attendance >= 22 {
        "A+"
    } else if score >= 85 && attendance >= 20 {
        "A"
    } else if score >= 70 && attendance >= 18 {
        "B"
    } else if score >= 60 {
        "C"
    } else {
        "D"
    }
}

على الرغم من أن هذا الكود يعمل، إلا أنه ينطوي على عدة مشكلات: فالشروط مبعثرة عبر سلسلة من عبارات «if-else»، مما يجعل قراءته صعبة، كما أنه لا يوجد فحص شامل — فإذا أُضيفت قواعد تقييم في المستقبل، فسيكون من السهل تجاهلها. علاوة على ذلك، فإن الارتباط بين الدرجات والحضور ليس واضحًا بما فيه الكفاية.

(2) مناهج متقدمة لمطابقة الأنماط في لغة Rust

RUST
fn rate_employee(score: u32, attendance: u32) -> &'static str {
    match score {
        // Guard Requirements: Meeting the Score Requirement + Attendance Requirements Met
        s if s >= 95 && attendance >= 22 => "A+",
        s if s >= 85 && attendance >= 20 => "A",
        s if s >= 70 && attendance >= 18 => "B",
        s if s >= 60 => "C",
        _ => "D",  // Fallback: score < 60
    }
}

fn main() {
    let employees = [
        ("Alice", 98, 23),
        ("Bob", 88, 21),
        ("Charlie", 88, 17),  // High scores but insufficient attendance
        ("Diana", 72, 19),
        ("Eve", 55, 20),
    ];

    for (name, score, attendance) in &employees {
        let rating = rate_employee(*score, *attendance);
        println!("{:8} | Score: {:2} | Attendance: {:2} days | Rating: {}",
            name, score, attendance, rating);
    }
}

الناتج:

TEXT 📖 للعرض فقط
Alice    | Score: 98 | Attendance: 23 days | Rating: A+
Bob      | Score: 88 | Attendance: 21 days | Rating: A
Charlie  | Score: 88 | Attendance: 17 days | Rating: B
Diana    | Score: 72 | Attendance: 19 days | Rating: B
Eve      | Score: 55 | Attendance: 20 days | Rating: D

match يوضح الحارس شروط كل فرع على الفور: حيث تظهر بوضوح العلاقة "AND" بين الدرجة والحضور. _ ويضمن الفرع الشامل استيفاء جميع الحالات. علاوة على ذلك، فإن دلالة s if s >= ... بالنسبة لنطاقات الدرجات المختلفة أكثر بديهية من دلالة else if.



3. نظرة عامة على المطابقة المتقدمة للأنماط

(1) خريطة مفاهيمية

100%
graph TB
    A[Advanced Pattern Matching] --> B[match Guard]
    A --> C[@ Bind]
    A --> D[Multimode |]
    A --> E[Range Matching]
    A --> F[matches! Macro]
    A --> G[Deconstruction Patterns]
    B --> B1["match x { n if n > 10 => ... }"]
    C --> C1["match x { e @ 1..=5 => ... }"]
    D --> D1["match x { 1 | 3 | 5 => ... }"]
    E --> E1["match x { 1..=10 => ... }"]
    F --> F1["if matches!(x, 1..=5) { ... }"]
    G --> G1["let Point { x, y } = p;"]
    G --> G2["match opt { Some(v @ 1..=10) => ... }"]

(2) مقارنة بين طرق المطابقة

الطريقة الصيغة متى تُستخدم مثال
المطابقة الأساسية match x { PAT => .. } مطابقة القيمة البسيطة match x { 1 => "one" }
حارس المباراة match x { PAT if COND => .. } المباراة + شروط إضافية n if n > 10 && n % 2 == 0
@ الربط e @ PAT => .. قيمة الربط عند التطابق e @ 1..=10 => e
أوضاع متعددة | PAT1 | PAT2 => .. تتشارك الأوضاع المتعددة نفس الفرع 1 | 3 | 5 => "odd"
النطاق ..= PAT1..=PAT2 => .. يطابق نطاقًا من القيم 1..=5 => "small"
ماكرو "matches!" matches!(x, PAT) نتيجة منطقية فقط if matches!(x, 1..=5)
التفكيك let PAT = value تفكيك الأنواع المركبة let (a, b) = pair

(3) مرجع سريع لأنواع الأنماط

نوع النمط الصيغة الهدف المطابق مثال
النص الحرفي 1 / "hello" القيمة الدقيقة match x { 1 => ... }
ربط المتغير x أي قيمة، مرتبطة بـ x match x { n => ... }
حرف البدل _ أي قيمة، يتم تجاهلها match x { _ => ... }
أوضاع متعددة 1 | 2 | 3 قيم متعددة match x { 1 | 2 => ... }
النطاق 1..=5 نطاق الفاصل المغلق match x { 1..=5 => ... }
تحليل المجموعات (a, b) المجموعات match pair { (x, y) => ... }
تفكيك الهياكل Point { x, y } الهياكل match p { Point { x, y } => ... }
تحليل عمليات التعداد Some(v) أشكال التعداد المختلفة match opt { Some(v) => ... }
@ الربط e @ 1..=10 النطاق + الربط match x { e @ 1..=10 => ... }
الحراسة x if x > 0 الوضع + الشروط match x { n if n > 0 => ... }
تجاهل الباقي .. تجاهل بعض الحقول match p { Point { x, .. } => ... }


4. أمثلة على المطابقة المتقدمة

(1) ▶ المثال:Match Guard + @ Binding + Multi-Mode (مستوى الصعوبة ⭐⭐)

RUST
// ============================================
// Comprehensive Example: Employee Performance Rating System
// Display match Guard, @ Bind, Multi-pattern
// ============================================

#[derive(Debug)]
enum Department {
    Engineering,
    Sales,
    HR,
    Management,
}

#[derive(Debug)]
struct Employee {
    name: String,
    score: u32,
    attendance: u32,
    department: Department,
}

impl Employee {
    /// Rate employee using advanced pattern matching.
    /// Returns (rating, bonus_percentage).
    fn rate(&self) -> (&'static str, u32) {
        match (self.score, self.attendance) {
            // @ binding: capture the matched score value
            s @ 95..=100 if self.attendance >= 22 => {
                println!("  [@ binding] score {} captured for A+ rating", s);
                ("A+", 30)
            }
            s @ 85..=94 if self.attendance >= 20 => {
                println!("  [@ binding] score {} captured for A rating", s);
                ("A", 20)
            }
            s @ 70..=84 if self.attendance >= 18 => {
                println!("  [@ binding] score {} captured for B rating", s);
                ("B", 10)
            }
            // Multi-pattern: 60..=69 OR exactly 70 with low attendance
            60..=69 | 70..=84 => {
                ("C", 5)  // No @ binding needed here
            }
            // match guard with combined conditions
            s if s < 60 => {
                println!("  [guard] score {} is below 60, rating D", s);
                ("D", 0)
            }
            // Catch-all: should not reach normally
            _ => {
                println!("  [wildcard] unexpected combination");
                ("Unknown", 0)
            }
        }
    }

    /// Check if this employee qualifies for special bonus
    /// using matches! macro.
    fn has_special_bonus(&self) -> bool {
        // matches! returns true if the pattern matches
        matches!(self.department, Department::Engineering | Department::Management)
            && self.score >= 90
    }
}

fn main() {
    let employees = vec![
        Employee {
            name: String::from("Alice"),
            score: 97,
            attendance: 23,
            department: Department::Engineering,
        },
        Employee {
            name: String::from("Bob"),
            score: 88,
            attendance: 21,
            department: Department::Sales,
        },
        Employee {
            name: String::from("Charlie"),
            score: 88,
            attendance: 17,
            department: Department::HR,
        },
        Employee {
            name: String::from("Diana"),
            score: 65,
            attendance: 20,
            department: Department::HR,
        },
        Employee {
            name: String::from("Eve"),
            score: 42,
            attendance: 15,
            department: Department::Management,
        },
    ];

    for emp in &employees {
        println!("{}:", emp.name);
        let (rating, bonus) = emp.rate();
        let special = emp.has_special_bonus();
        println!("  Rating: {}, Bonus: {}%, Special: {}",
            rating, bonus, special);
        println!();
    }
}

الناتج:

TEXT 📖 للعرض فقط
Alice:
  [@ binding] score 97 captured for A+ rating
  Rating: A+, Bonus: 30%, Special: true

Bob:
  [@ binding] score 88 captured for A rating
  Rating: A, Bonus: 20%, Special: false

Charlie:
  [@ binding] score 88 captured for B rating
  Rating: B, Bonus: 10%, Special: false

Diana:
  Rating: C, Bonus: 5%, Special: false

Eve:
  [guard] score 42 is below 60, rating D
  Rating: D, Bonus: 0%, Special: true

يوضح هذا المثال بشكل شامل ثلاث تقنيات مطابقة متقدمة: @ تربط القيم الملتقطة لاستخدامها لاحقًا؛ if تستخدم الحراس لإضافة شروط إضافية (مثل متطلبات الحضور)؛ | تستخدم الوضع المتعدد للسماح لنطاقات مختلفة بمشاركة نفس الفرع؛ وmatches! تستخدم ماكروًّا لتحديد «ما إذا كان ينتمي إلى أحد المتغيرات العديدة» بشكل موجز.


(2) ▶ المثال:تفكيك الهياكل المتداخلة وقوائم التعداد (مستوى الصعوبة ⭐⭐⭐)

RUST
// ============================================
// Nested Deconstruction: Matching Enums in Structures, Tuples in Enumerations
// ============================================

#[derive(Debug)]
enum TaskStatus {
    Pending,
    InProgress,
    Completed { finished_at: String, reviewer: String },
    Blocked { reason: String, blocked_by: String },
}

#[derive(Debug)]
struct Task {
    id: u32,
    title: String,
    status: TaskStatus,
    priority: u8,  // 1 (highest) to 5 (lowest)
}

fn analyze_task(task: &Task) {
    // Destructure the Task struct directly in match
    match task {
        // Multi-pattern: priority 1 or 2 with any status
        Task { priority: 1..=2, .. } => {
            println!("  [range] High priority task (level {})", task.priority);
        }
        // Destructure both Task and TaskStatus::Completed
        Task {
            id,
            title,
            status:
                TaskStatus::Completed {
                    finished_at,
                    reviewer,
                },
            priority,
        } => {
            println!("  [nested destructure] Task #{} '{}' completed by {} at {} (priority {})",
                id, title, reviewer, finished_at, priority);
        }
        // Destructure TaskStatus::Blocked with @ binding on reason
        Task {
            status:
                TaskStatus::Blocked {
                    reason,
                    blocked_by,
                },
            ..
        } => {
            println!("  [@ binding] Task '{}' blocked by {}: {}",
                task.title, blocked_by, reason);
        }
        // Match guard on enum variant
        Task {
            status: TaskStatus::InProgress,
            priority,
            ..
        } if *priority <= 3 => {
            println!("  [guard] Important in-progress task (priority {})", priority);
        }
        // Wildcard for remaining
        _ => {
            println!("  [wildcard] Task '{}': status {:?}", task.title, task.status);
        }
    }
}

fn main() {
    let tasks = vec![
        Task {
            id: 1,
            title: String::from("Security audit"),
            status: TaskStatus::Completed {
                finished_at: String::from("2026-07-01"),
                reviewer: String::from("Alice"),
            },
            priority: 1,
        },
        Task {
            id: 2,
            title: String::from("Update dependencies"),
            status: TaskStatus::Blocked {
                reason: String::from("Waiting for approval"),
                blocked_by: String::from("Manager"),
            },
            priority: 2,
        },
        Task {
            id: 3,
            title: String::from("Write documentation"),
            status: TaskStatus::InProgress,
            priority: 3,
        },
        Task {
            id: 4,
            title: String::from("Fix typo in README"),
            status: TaskStatus::Pending,
            priority: 5,
        },
    ];

    for task in &tasks {
        println!("Task #{}: {}", task.id, task.title);
        analyze_task(task);
        println!();
    }
}

الناتج:

TEXT 📖 للعرض فقط
Task #1: Security audit
  [nested destructure] Task #1 'Security audit' completed by Alice at 2026-07-01 (priority 1)

Task #2: Update dependencies
  [range] High priority task (level 2)

Task #3: Write documentation
  [guard] Important in-progress task (priority 3)

Task #4: Fix typo in README
  [wildcard] Task 'Fix typo in README': status Pending

يُعد التفكيك المتداخل إحدى الميزات القوية لمطابقة الأنماط في لغة Rust: حيث يمكنك تفكيك الهياكل (structs) والقوائم (enums) والمجموعات (tuples) في آن واحد ضمن فرع match واحد. يتجاهل .. الحقول التي لا تهمك، بينما يقوم @ بربط القيم الداخلية والتقاطها. لاحظ أن Task { priority: 1..=2, .. } يطابق المهام ذات أي أولوية تساوي 1 أو 2 — لأنه على الرغم من أن Blocked يأتي لاحقًا في النمط، فإن range يطابق المهام ذات الأولوية = 2 أولاً.


(3) ▶ المثال:دمج الماكرو matches! مع if let (مستوى الصعوبة: ⭐⭐)

RUST
// ============================================
// matches! Macro: Simple Boolean Pattern Matching
// ============================================

#[derive(Debug, PartialEq)]
enum HttpStatus {
    Ok,
    NotFound,
    ServerError(u16),
    Redirect(u16),
}

/// Check if a status is a success (2xx).
fn is_success(status: &HttpStatus) -> bool {
    matches!(status, HttpStatus::Ok)
}

/// Check if a status is a server error (5xx).
fn is_server_error(status: &HttpStatus) -> bool {
    matches!(status, HttpStatus::ServerError(_))
}

/// Check if a status is a redirect (3xx) with specific code.
fn is_redirect_to(status: &HttpStatus, code: u16) -> bool {
    matches!(status, HttpStatus::Redirect(c) if *c == code)
}

/// Get status category using multiple matches! checks.
fn categorize(status: &HttpStatus) -> &'static str {
    if matches!(status, HttpStatus::Ok) {
        "Success"
    } else if matches!(status, HttpStatus::Redirect(301 | 302)) {
        "Temporary Redirect"
    } else if matches!(status, HttpStatus::Redirect(_)) {
        "Other Redirect"
    } else if matches!(status, HttpStatus::NotFound) {
        "Not Found (404)"
    } else if matches!(status, HttpStatus::ServerError(500..=599)) {
        "Server Error"
    } else {
        "Unknown"
    }
}

fn main() {
    let statuses = vec![
        HttpStatus::Ok,
        HttpStatus::NotFound,
        HttpStatus::Redirect(301),
        HttpStatus::Redirect(307),
        HttpStatus::ServerError(500),
        HttpStatus::ServerError(503),
    ];

    for status in &statuses {
        println!("{:?}:", status);
        println!("  is_success: {}", is_success(status));
        println!("  is_server_error: {}", is_server_error(status));
        println!("  is_redirect_to_301: {}", is_redirect_to(status, 301));
        println!("  category: {}", categorize(status));

        // if let with matches!-style pattern
        if let HttpStatus::ServerError(code) = status {
            println!("  >> Server error code: {}", code);
        }
        println!();
    }
}

الناتج:

TEXT 📖 للعرض فقط
Ok:
  is_success: true
  is_server_error: false
  is_redirect_to_301: false
  category: Success

NotFound:
  is_success: false
  is_server_error: false
  is_redirect_to_301: false
  category: Not Found (404)

Redirect(301):
  is_success: false
  is_server_error: false
  is_redirect_to_301: true
  category: Temporary Redirect

Redirect(307):
  is_success: false
  is_server_error: false
  is_redirect_to_301: false
  category: Other Redirect

ServerError(500):
  is_success: false
  is_server_error: true
  is_redirect_to_301: false
  category: Server Error

ServerError(503):
  is_success: false
  is_server_error: true
  is_redirect_to_301: false
  category: Server Error

يُرجع الماكرو matches! قيمة من نوع bool، وهي مناسبة لمطابقة الأنماط في شروط if. وهو يدعم جميع صيغ الأنماط، بما في ذلك شروط if، والأنماط المتعددة، ومطابقة النطاقات. على عكس if let، لا يقوم matches! بربط المتغيرات؛ بل يرجع فقط true/false — وهو الخيار الأكثر إيجازًا عندما تحتاج فقط إلى تقييم شرط دون استرداد قيمة.


(4) ▶ المثال:تمرين شامل — مُقيِّم التعبيرات (مستوى الصعوبة ⭐⭐⭐)

RUST
// ============================================
// Comprehensive Example: Implementing Expression Evaluation Using Nested Pattern Matching
// ============================================

#[derive(Debug, Clone)]
enum Expr {
    Number(f64),
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Neg(Box<Expr>),
}

fn eval(expr: &Expr) -> Option<f64> {
    match expr {
        Expr::Number(n) => Some(*n),
        Expr::Add(a, b) => Some(eval(a)? + eval(b)?),
        Expr::Sub(a, b) => Some(eval(a)? - eval(b)?),
        Expr::Mul(a, b) => Some(eval(a)? * eval(b)?),
        Expr::Div(a, b) => {
            let divisor = eval(b)?;
            if divisor == 0.0 { None } else { Some(eval(a)? / divisor) }
        }
        Expr::Neg(a) => Some(-eval(a)?),
    }
}

fn expr_to_string(expr: &Expr) -> String {
    match expr {
        Expr::Number(n) => format!("{:.0}", n),
        Expr::Add(a, b) => format!("({} + {})", expr_to_string(a), expr_to_string(b)),
        Expr::Sub(a, b) => format!("({} - {})", expr_to_string(a), expr_to_string(b)),
        Expr::Mul(a, b) => format!("({} * {})", expr_to_string(a), expr_to_string(b)),
        Expr::Div(a, b) => format!("({} / {})", expr_to_string(a), expr_to_string(b)),
        Expr::Neg(a) => format!("-{}", expr_to_string(a)),
    }
}

fn main() {
    let expr1 = Expr::Add(
        Box::new(Expr::Number(10.0)),
        Box::new(Expr::Mul(Box::new(Expr::Number(3.0)), Box::new(Expr::Number(4.0)))),
    );
    let expr2 = Expr::Div(
        Box::new(Expr::Sub(Box::new(Expr::Number(20.0)), Box::new(Expr::Number(5.0)))),
        Box::new(Expr::Number(3.0)),
    );
    let expr3 = Expr::Neg(Box::new(Expr::Number(42.0)));
    let expr4 = Expr::Div(Box::new(Expr::Number(10.0)), Box::new(Expr::Number(0.0)));

    let exprs = [expr1, expr2, expr3, expr4];
    for (i, expr) in exprs.iter().enumerate() {
        let s = expr_to_string(expr);
        match eval(expr) {
            Some(val) => println!("Expression{}: {} = {:.2}", i + 1, s, val),
            None => println!("Expression{}: {} = Error (Division by Zero)", i + 1, s),
        }
    }
}

الناتج:

TEXT 📖 للعرض فقط
Expression1: (10 + (3 * 4)) = 22.00
Expression2: ((20 - 5) / 3) = 5.00
Expression3: -42 = -42.00
Expression4: (10 / 0) = Error (Division by Zero)

يُعد التعداد التكراري المقترن بتفكيك المتغيرات المتداخلة أحد أقوى تطبيقات مطابقة الأنماط. Box<Expr> يتيح للتعدادات الإشارة إلى نفسها (نظرًا لأن Box هو مؤشر ذو حجم ثابت). eval يستخدم عامل ? لنقل الأخطاء غير الصفرية بطريقة أنيقة.


(5) ▶ المثال:مطابقة الأنماط وهياكل البيانات الشبيهة بـ JSON (مستوى الصعوبة ⭐⭐⭐)

RUST
// ============================================
// Processing Dynamically Typed Data Using Pattern Matching
// ============================================

#[derive(Debug, Clone)]
enum Value {
    Null,
    Bool(bool),
    Number(f64),
    String(String),
    Array(Vec<Value>),
    Object(Vec<(String, Value)>),
}

fn type_name(val: &Value) -> &str {
    match val {
        Value::Null => "null",
        Value::Bool(_) => "bool",
        Value::Number(_) => "number",
        Value::String(_) => "string",
        Value::Array(_) => "array",
        Value::Object(_) => "object",
    }
}

fn deep_count(val: &Value) -> usize {
    match val {
        Value::Array(items) => items.iter().map(deep_count).sum::<usize>() + 1,
        Value::Object(entries) => entries.iter().map(|(_, v)| deep_count(v)).sum::<usize>() + 1,
        _ => 1,
    }
}

fn find_key<'a>(val: &'a Value, key: &str) -> Option<&'a Value> {
    match val {
        Value::Object(entries) => entries.iter().find(|(k, _)| k == key).map(|(_, v)| v),
        _ => None,
    }
}

fn main() {
    let data = Value::Object(vec![
        ("name".into(), Value::String("Alice".into())),
        ("age".into(), Value::Number(30.0)),
        ("active".into(), Value::Bool(true)),
        ("scores".into(), Value::Array(vec![
            Value::Number(95.0),
            Value::Number(88.0),
            Value::Number(92.0),
        ])),
        ("address".into(), Value::Object(vec![
            ("city".into(), Value::String("Beijing".into())),
            ("zip".into(), Value::Number(100000.0)),
        ])),
    ]);

    println!("Type: {}", type_name(&data));
    println!("Number of nodes: {}", deep_count(&data));

    if let Some(Value::String(name)) = find_key(&data, "name") {
        println!("Name: {}", name);
    }

    if let Some(Value::Array(scores)) = find_key(&data, "scores") {
        let avg: f64 = scores.iter()
            .filter_map(|v| if let Value::Number(n) = v { Some(*n) } else { None })
            .sum::<f64>() / scores.len() as f64;
        println!("Average Score: {:.1}", avg);
    }

    if let Some(Value::Object(addr)) = find_key(&data, "address") {
        if let Some(Value::String(city)) = find_key(&Value::Object(addr.clone()), "city") {
            println!("City: {}", city);
        }
    }
}

الناتج:

TEXT 📖 للعرض فقط
Type: object
Number of nodes: 11
Name: Alice
Average Score: 91.7
City: Beijing

استخدم القوائم (enumerations) لمحاكاة البيانات ذات الأنواع الديناميكية (مثل JSON)، واستخراجها والتكرار عليها بأمان باستخدام مطابقة الأنماط. find_key استخدم if let للوصول الآمن، وfilter_map بالاقتران مع مطابقة الأنماط لتصفية القيم في المصفوفة وتحويلها.



❓ أسئلة شائعة

س كيف يتم تحديد أولوية الشرط match (if guard) على الفرع match؟
ج الشرط match هو شرط داخل فرع — حيث تتم مطابقة النمط أولاً، ثم يتم تقييم الشرط. وإذا عاد الشرط بقيمة false، ينتقل البرنامج إلى الفرع التالي (ولا ينتقل مباشرةً إلى الفرع الذي يليه!). ويمكن استخدام المتغيرات المرتبطة بمطابقة النمط في شرط الحراسة.
س ما الفرق بين الربط باستخدام @ واستخدام المتغير مباشرةً؟
ج الربط باستخدام @ يلتقط قيمةً أثناء مطابقة نمط معين. على سبيل المثال، e @ 1..=10 تعني «إذا كانت القيمة بين 1 و10، فقم بربط تلك القيمة بـ e». أما كتابة x مباشرةً فتطابق أي قيمة وتربطها بـ x. @ تسمح لك بتقييد النطاق مع الاستمرار في استخدام تلك القيمة.
س ما الفرق بين .. و _ في مطابقة الأنماط؟
ج .. يطابق أي عدد من العناصر (ويتجاهلها)، بينما _ يطابق موضعًا واحدًا. عند تفكيك بنية (struct)، يتجاهل Struct { a, .. } جميع الحقول الأخرى؛ أما في التوبول (tuple)، فإن (x, .., z) يطابق العنصرين الأول والأخير. _ يتجاهل موضعًا واحدًا فقط. .. لا يمكن استخدامه إلا مرة واحدة في نفس النمط.
س ما الفرق بين الماكرو matches! وif let؟
ج يُرجع matches! قيمة bool (دون ربط متغير)، بينما يقوم if let بربط متغير وتنفيذ كتلة التعليمات البرمجية. إذا كنت تحتاج فقط إلى التحقق من «ما إذا كان هناك تطابق» دون الحاجة إلى القيمة المطابقة، فاستخدم matches!. أما إذا كنت بحاجة إلى تحليل القيمة واستخدامها، فاستخدم if let أو match.
س الوضع المتعدد | هل يمكن استخدامه مع متغيرات مختلفة من قائمة التعداد؟
ج نعم، ولكن يجب أن تكون المتغيرات من نفس النوع وأن تحتوي على نفس عدد عناصر البيانات (أو لا تحتوي على أي عناصر على الإطلاق). على سبيل المثال، يُقبل استخدام Some(1) | Some(2)، ولكن لا يُقبل استخدام Some(1) | None، لأن Some تحتوي على عناصر بيانات بينما None لا تحتوي على أي عناصر.
س ما هي الأنواع المدعومة لمطابقة النطاق ..=؟
ج يتم دعم أي نوع عدد صحيح يطبق PartialOrd (i8-u128، u8-u128) ونوع char. على سبيل المثال، match c { 'a'..='z' => "lowercase", 'A'..='Z' => "uppercase", _ => "other" }. لا يتم دعم مطابقة النطاق لـ f64.

📖 ملخص


📝 تمارين

  1. الصعوبة ⭐: اكتب دالة fn describe_number(n: i32) -> &'static str تستخدم الدالة match ومطابقة النطاق: تُرجع الدالة 1..=10 القيمة "صغير"، وتُرجع الدالة 11..=100 القيمة "متوسط"، وتُرجع الدالة 101..=1000 القيمة "كبير"، بينما تُرجع جميع القيم الأخرى "خارج النطاق". اختبر الدالة باستخدام القيم 5 و50 و500 و5000 في الدالة main.

  2. الصعوبة ⭐⭐: عرّف قائمة Temperature تتضمن متغيرين: Celsius(f64) وFahrenheit(f64). اكتب دالة fn describe_temp(temp: &Temperature) -> &'static str تستخدم الماكرو matches! وشرط الحراسة if لتحديد: إذا كانت درجة الحرارة بالسيلزيوس أكبر من 30 أو بالفهرنهايت أكبر من 86، فقم بإرجاع "hot"؛ وإذا كانت درجة الحرارة بالسيلزيوس أقل من 0 أو بالفهرنهايت أقل من 32، فقم بإرجاع "cold"؛ وإلا، فقم بإرجاع "moderate". اختبر درجات الحرارة الأربع في الدالة main.

  3. الصعوبة ⭐⭐⭐: عرّف بنية Order تحتوي على id: u32 وitems: Vec<String> وtotal: f64 وstatus: OrderStatus (التعداد: Pending، Shipped { tracking: String }، Delivered { date: String }). قم بتنفيذ دالة fn summary(&self) -> String التي تستخدم تفكيك متداخل وحراس match لإرجاع رسائل ملخص مختلفة بناءً على الحالة والمبلغ الإجمالي (على سبيل المثال، بالنسبة للطلبات التي تم شحنها والتي يزيد مجموع قيمتها عن 1,000، اعرض "تم شحن طلب عالي القيمة، التتبع: xxx"). في الدالة main، أنشئ ثلاث طلبات واطبع ملخصاتها.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%