Rust: حلقات Rust والتكرار

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

الحلقة في لغة Rust ليست مجرد «حلقة لا نهائية» بسيطة — بل إنها «تُخرج» قيمة الحساب الأخير.

لكل نوع من أنواع الحلقات الثلاثة حالة استخدام خاصة به: loop الحلقات اللانهائية (مع قيم إرجاع)، while الحلقات الشرطية، وfor التكرار على المجموعات.


1. ما ستتعلمه



2. قصة مستكشف المتاهة

(1) المعاناة: الضياع في متاهة

يعمل أليكس على تطوير لعبة متاهة. وتتكون المتاهة من هيكل متداخل مكون من ثلاث طبقات:

TEXT 📖 للعرض فقط
Outer layer (Dungeon) -> Middle layer (Room) -> Inner layer (Treasure Chest)

يتعين على اللاعب التوغل أكثر فأكثر للعثور على المخرج، لكنه يجد صعوبة في كتابة الكود:

«لو أمكننا تسمية كل حلقة، لكان بإمكاننا القفز إلى أي مكان نريده...»

(2) حل لغة «Rust» للحلقات

RUST
fn main() {
    let mut found_exit = false;
    let maze = [
        ["empty", "empty", "key"],
        ["empty", "monster", "empty"],
        ["exit", "empty", "trap"],
    ];

    // Outer Label 'outer Naming Dungeon Cycles
    'outer: for (row, floor) in maze.iter().enumerate() {
        println!("Enter the dungeon, Floor #{}", row + 1);
        for (col, room) in floor.iter().enumerate() {
            match *room {
                "exit" => {
                    println!("  Find the Exit!Location: ({}, {})", row, col);
                    found_exit = true;
                    break 'outer;  // Exit two nested loops immediately
                }
                "key" => println!("  Get the keys (Location: {},{})", row, col),
                "monster" => println!("  There's a monster!Skip this room"),
                _ => println!("  Vacant Room {}", col),
            }
        }
    }

    println!("Have you found the exit?: {}", found_exit);
}

تتيح تسميات الحلقات في لغة Rust ('outer) break الخروج من الحلقات على أي مستوى. وهذا أكثر أمانًا من goto — فهو لا يقفز إلى موقع عشوائي في الكود، بل يكتفي بالخروج من الحلقة فقط.



3. مقارنة بين الحلقات الثلاث

100%
graph TB
    A[Rust Loop] --> B[loop: Infinite Loop]
    A --> C[while: Conditional Loops]
    A --> D[for: Set Iteration]
    B --> E[Until break up to and including]
    B --> F[Available break Return Value]
    C --> G[Check the condition before each loop]
    D --> H[Iterating Through a Set Automatically/Scope]
    D --> I[Most Commonly Used,Safest]
الخصائص loop while for
متى تُستخدم شرط إنهاء غير محدد تعتمد على الشرط التكرار على مجموعة أو نطاق
قيمة الإرجاع break value قد تُرجع قيمة لا يمكنها إرجاع قيمة لا يمكنها إرجاع قيمة
حلقة لا نهائية أصلية while true غير مناسب
الأداء الأمثل (يعرف المُجمِّع أن العملية ستتكرر) أسوأ قليلاً (يتحقق من الشرط في كل مرة) الأمثل (يتم تشغيله مباشرةً بواسطة المُكرر)
حالات الاستخدام إعادة المحاولة/الاستقصاء الانتظار المشروط التكرار عبر المصفوفات/المتجهات/النطاقات

(2) مقارنة بين break وcontinue

الكلمة المفتاحية الوظيفة يمكن أن تُرجع قيمة تُستخدم مع العلامات
break الخروج من الحلقة الحالية break value; (في الحلقة فقط) break 'label;
continue تخطي بقية هذه الحلقة لا يمكن continue 'label;

(3) تعبيرات النطاق

الرمز المعنى يشمل القيمة النهائية مثال
start..end فترة شبه مفتوحة لا 0..5 → 0، 1، 2، 3، 4
start..=end فترة مغلقة نعم 0..=5 → 0، 1، 2، 3، 4، 5
..end من 0 إلى النهاية لا ..3 → 0، 1، 2
start.. من البداية إلى النهاية 3.. → 3، 4، 5، ...


4. أمثلة على الحلقات

(1) ▶ المثال:الحلقات اللانهائية باستخدام loop وقيم الإرجاع باستخدام break (مستوى الصعوبة ⭐)

RUST
// ============================================
// loop Loop:A simulation of the "Guess the Number" game"Let's try again"
// ============================================

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;
        if counter == 5 {
            break counter * 2;  // break Can have a return value!
        }
    };

    println!("Loop ran 5 times, break returned: {}", result);

    // Real-World Scenarios:Keep trying until you succeed
    let mut attempts = 0;
    let success = loop {
        attempts += 1;
        if attempts >= 3 {
            break true;
        }
        // Simulate a failed operation,Keep trying
    };
    println!("Retry {} Success on the next attempt: {}", attempts, success);
}

الناتج:

TEXT 📖 للعرض فقط
Loop ran 5 times, break returned: 10
Retry 3 Success on the next attempt: true

loop هي بنية الحلقة الوحيدة في لغة Rust التي يمكنها إرجاع قيمة. ويمكن أن تتبع قيمة الإرجاع الكلمة الرئيسية break مباشرةً، دون الحاجة إلى متغير إضافي. وهذا مفيد جدًّا في نمط «المحاولة حتى النجاح».


(2) ▶ المثال:while حلقة شرطية (مستوى الصعوبة ⭐)

RUST
// ============================================
// while Loop:Countdown in Decreasing Order
// ============================================

fn main() {
    let mut countdown = 5;

    while countdown > 0 {
        println!("Countdown: {}...", countdown);
        countdown -= 1;
    }

    println!("Launch!");
}

الناتج:

TEXT 📖 للعرض فقط
Countdown: 5...
Countdown: 4...
Countdown: 3...
Countdown: 2...
Countdown: 1...
Launch!

while تحقق من الشرط قبل بدء كل تكرار. إذا كان الشرط هو false، فتخطى جسم الحلقة بالكامل. وهذا مناسب للحالات التي يكون فيها «عدد التكرارات غير معروف، لكن شرط الإنهاء معروف».


(3) ▶ المثال:التكرار باستخدام for والنطاقات (مستوى الصعوبة ⭐⭐)

RUST
// ============================================
// for Loop:Iteration Range,Arrays and Strings
// ============================================

fn main() {
    // 1. Range Iteration: 0..5 is 0 to 4 (Excludes 5)
    println!("-- Scope 0..5 --");
    for i in 0..5 {
        print!("{} ", i);
    }
    println!();

    // 2. Closing Range:0..=5 Includes 5
    println!("-- Scope 0..=5 --");
    for i in 0..=5 {
        print!("{} ", i);
    }
    println!();

    // 3. Iterate through an array
    let fruits = ["apple", "banana", "cherry"];
    println!("-- List of Fruits --");
    for fruit in &fruits {
        println!("{}", fruit);
    }

    // 4. Indexed Iteration(enumerate)
    println!("-- Indexed Iteration --");
    for (index, fruit) in fruits.iter().enumerate() {
        println!("Fruit #{}: {}", index, fruit);
    }
}

الناتج:

TEXT 📖 للعرض فقط
-- Scope 0..5 --
0 1 2 3 4
-- Scope 0..=5 --
0 1 2 3 4 5
-- List of Fruits --
apple
banana
cherry
-- Indexed Iteration --
Fruit #0: apple
Fruit #1: banana
Fruit #2: cherry

for هي الطريقة الأكثر توصيةً للتكرار في لغة Rust. فهي تمنع الوصول خارج النطاق وتتعامل تلقائيًا مع عملية التكرار. 0..n هو فترة نصف مفتوحة (باستثناء n)، و0..=n هي فترة مغلقة (بما في ذلك n). .enumerate() تُعيّن مؤشرًا لكل عنصر.


(4) ▶ المثال:تسميات الحلقات والحلقات المتداخلة (مستوى الصعوبة ⭐⭐⭐)

RUST
// ============================================
// Loop Label:break 'label Breaking Out of Multiple Levels of Nesting
// ============================================

fn main() {
    let matrix = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ];

    let mut found = 0;

    // 'search Outer Loop for Tag Marking
    'search: for (i, row) in matrix.iter().enumerate() {
        for (j, &val) in row.iter().enumerate() {
            if val == 5 {
                println!("Find the Target 5 At the location ({}, {})", i, j);
                found = val;
                break 'search;  // Exit two nested loops immediately!
            }
        }
    }

    println!("Values found: {}", found);

    // continue It can also be used in conjunction with tags.
    'outer: for x in 0..3 {
        for y in 0..3 {
            if x == y {
                continue 'outer;  // Skip the remaining inner layers,Continue to the next outer layer
            }
            println!("x={}, y={}", x, y);
        }
    }
}

الناتج:

TEXT 📖 للعرض فقط
Find the Target 5 At the location (1, 1)
Values found: 5
x=1, y=0
x=2, y=0
x=2, y=1

بدون تسمية، لا يؤثر break وcontinue إلا على الحلقة الأعمق. ومن خلال إضافة تسمية ('name)، يمكنك التحكم في الحلقات على أي مستوى. وهذه طريقة أكثر تحكمًا في «الخروج» مقارنة بـ goto.


(5) ▶ المثال:تمرين شامل — FizzBuzz وجدول الضرب (مستوى الصعوبة ⭐⭐)

RUST
// ============================================
// Comprehensive Cycle Practice:FizzBuzz + The 9×9 Multiplication Table
// ============================================

fn main() {
    println!("=== FizzBuzz (1-30) ===");
    for n in 1..=30 {
        match (n % 3, n % 5) {
            (0, 0) => print!("FizzBuzz "),
            (0, _) => print!("Fizz "),
            (_, 0) => print!("Buzz "),
            _ => print!("{} ", n),
        }
        if n % 10 == 0 { println!(); }
    }
    println!();

    println!("\n=== The 9×9 Multiplication Table ===");
    for i in 1..=9 {
        for j in 1..=i {
            print!("{}×{}={:<4}", j, i, i * j);
        }
        println!();
    }

    println!("\n=== while let Simulated Read ===");
    let mut queue = vec![10, 20, 30, 40, 0];
    while let Some(item) = queue.pop() {
        if item == 0 {
            println!("Encountered a termination signal,Stop Processing");
            break;
        }
        println!("Projects in Progress: {}", item);
    }

    println!("\n=== loop Retry Mode ===");
    let attempts = try_connect(3);
    println!("Connection Results: {}", attempts);
}

fn try_connect(max_retries: u32) -> bool {
    let mut attempt = 0;
    loop {
        attempt += 1;
        println!("Attempt #{} to connect...", attempt);
        if attempt >= max_retries {
            break true;
        }
    }
}

الناتج:

TEXT 📖 للعرض فقط
=== FizzBuzz (1-30) ===
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 
11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz 
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 

=== The 9×9 Multiplication Table ===
1×1=1   
1×2=2   2×2=4   
1×3=3   2×3=6   3×3=9   
1×4=4   2×4=8   3×4=12  4×4=16  
1×5=5   2×5=10  3×5=15  4×5=20  5×5=25  
1×6=6   2×6=12  3×6=18  4×6=24  5×6=30  6×6=36  
1×7=7   2×7=14  3×7=21  4×7=28  5×7=35  6×7=42  7×7=49  
1×8=8   2×8=16  3×8=24  4×8=32  5×8=40  6×8=48  7×8=56  8×8=64  
1×9=9   2×9=18  3×9=27  4×9=36  5×9=45  6×9=54  7×9=63  8×9=72  9×9=81  

=== while let Simulated Read ===
Projects in Progress: 40
Projects in Progress: 30
Projects in Progress: 20
Projects in Progress: 10
Encountered a termination signal,Stop Processing

=== loop Retry Mode ===
Attempt #1 to connect...
Attempt #2 to connect...
Attempt #3 to connect...
Connection Results: true

يتم تنفيذ FizzBuzz بطريقة أكثر أناقة باستخدام match لمطابقة أنماط التوبول؛ بينما تستخدم جدول الضرب نمط for + النطاق ذي المستويين؛ ويُعد while let مناسبًا للتعامل مع نمط الحلقة «الاستمرار طالما تم استرداد قيمة»؛ أما loop + break فهما مناسبان لمنطق إعادة المحاولة.



❓ أسئلة شائعة

س ما الفرق بين loop وwhile true؟
ج loop هو الخيار المفضل في لغة Rust.
س ما الفرق بين for i in 0..n وfor i in 0..=n؟
ج يشير .. إلى فترة نصف مفتوحة (باستثناء n)، بينما يشير ..= إلى فترة مغلقة (بما في ذلك n).
س عند تكرار الممر عبر مصفوفة، ما الفرق بين &fruits و fruits.iter()؟
ج تستدعي &fruits ضمنيًا into_iter لاستعارة العناصر، في حين أن fruits.iter() أكثر صراحة ووضوحًا.
س كيف تُستخدم قيمة الإرجاع لـ break؟
ج يمكن لعبارة break الموجودة داخل loop أن تُرجع قيمة تمامًا مثل الدالة: let x = loop { break 42; };.
س ماذا أفعل إذا كان هناك عدد كبير جدًا من الحلقات المتداخلة؟
ج فكر في استخراج الحلقة الداخلية إلى دالة.

📖 ملخص


📝 تمارين

  1. الصعوبة ⭐: استخدم for للتنقل عبر 0..=10، مع عرض الأعداد الزوجية فقط (باستخدام if i % 2 == 0 للتحقق).
  2. الصعوبة ⭐⭐: قم بمحاكاة قيمة الإرجاع باستخدام loop + break: ابحث عن أول قيمة أكبر من 6 في vec![1, 3, 5, 7, 9, 11] وأرجعها؛ وإذا لم يتم العثور على أي قيمة، فأرجع -1.
  3. الصعوبة ⭐⭐⭐: استخدم حلقة for ذات الطبقتين لطباعة جدول الضرب 9×9، بحيث يتم تنسيق كل صف على أنه 1x1=1 1x2=2 …. فكر في كيفية استخدام تسميات الحلقة للتحكم في منطق فواصل الأسطر.
Web-Tutorial.com

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

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

100%