Rust: حلقات Rust والتكرار
آخر تحديث: 2026-08-26
الحلقة في لغة Rust ليست مجرد «حلقة لا نهائية» بسيطة — بل إنها «تُخرج» قيمة الحساب الأخير.
لكل نوع من أنواع الحلقات الثلاثة حالة استخدام خاصة به: loop الحلقات اللانهائية (مع قيم إرجاع)، while الحلقات الشرطية، وfor التكرار على المجموعات.
1. ما ستتعلمه
- استخدم
loopلإنشاء حلقة لا نهائية وإرجاع قيمة - استخدم
whileللتكرار الشرطي - استخدم
forللتكرار عبر المجموعات والنطاقات - استخدم
breakوcontinueللتحكم في عملية التكرار - استخدم علامة الحلقة للخروج من حلقة متداخلة
- استخدام تعبيرات النطاق
0..nو0..=n
2. قصة مستكشف المتاهة
(1) المعاناة: الضياع في متاهة
يعمل أليكس على تطوير لعبة متاهة. وتتكون المتاهة من هيكل متداخل مكون من ثلاث طبقات:
Outer layer (Dungeon) -> Middle layer (Room) -> Inner layer (Treasure Chest)
يتعين على اللاعب التوغل أكثر فأكثر للعثور على المخرج، لكنه يجد صعوبة في كتابة الكود:
- بعد أن عثرت على المفتاح في صندوق الكنز، أردت القفز إلى مستوى الغرفة — لكن
breakلا يمكنه القفز إلا مستوى واحدًا لأعلى - عليك تفتيش كل غرفة لفتح الباب — فهل يجب أن تستخدم
whileأمfor؟ - عدد الطوابق في المتاهة ثابت — لكن عدد الغرف في كل طابق يختلف.
«لو أمكننا تسمية كل حلقة، لكان بإمكاننا القفز إلى أي مكان نريده...»
(2) حل لغة «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. مقارنة بين الحلقات الثلاث
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 (مستوى الصعوبة ⭐)
// ============================================
// 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);
}
الناتج:
Loop ran 5 times, break returned: 10
Retry 3 Success on the next attempt: true
loopهي بنية الحلقة الوحيدة في لغة Rust التي يمكنها إرجاع قيمة. ويمكن أن تتبع قيمة الإرجاع الكلمة الرئيسيةbreakمباشرةً، دون الحاجة إلى متغير إضافي. وهذا مفيد جدًّا في نمط «المحاولة حتى النجاح».
(2) ▶ المثال:while حلقة شرطية (مستوى الصعوبة ⭐)
// ============================================
// while Loop:Countdown in Decreasing Order
// ============================================
fn main() {
let mut countdown = 5;
while countdown > 0 {
println!("Countdown: {}...", countdown);
countdown -= 1;
}
println!("Launch!");
}
الناتج:
Countdown: 5...
Countdown: 4...
Countdown: 3...
Countdown: 2...
Countdown: 1...
Launch!
whileتحقق من الشرط قبل بدء كل تكرار. إذا كان الشرط هوfalse، فتخطى جسم الحلقة بالكامل. وهذا مناسب للحالات التي يكون فيها «عدد التكرارات غير معروف، لكن شرط الإنهاء معروف».
(3) ▶ المثال:التكرار باستخدام for والنطاقات (مستوى الصعوبة ⭐⭐)
// ============================================
// 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);
}
}
الناتج:
-- 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) ▶ المثال:تسميات الحلقات والحلقات المتداخلة (مستوى الصعوبة ⭐⭐⭐)
// ============================================
// 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);
}
}
}
الناتج:
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 وجدول الضرب (مستوى الصعوبة ⭐⭐)
// ============================================
// 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;
}
}
}
الناتج:
=== 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).into_iter لاستعارة العناصر، في حين أن fruits.iter() أكثر صراحة ووضوحًا.break؟break الموجودة داخل loop أن تُرجع قيمة تمامًا مثل الدالة: let x = loop { break 42; };.📖 ملخص
loop: حلقة لا نهائية؛ استخدمbreak valueلإرجاع قيمةwhile: حلقة مشروطة؛ تتحقق من الشرط قبل كل تكرارfor: التكرار في الإعدادات/النطاق — يُوصى به بشدة- تعبيرات النطاق:
0..5(باستثناء 5)،0..=5(بما في ذلك 5) - يمكن لعلامة الحلقة
'labelالخروج من الحلقة أو تخطيها في أي مستوى breakالخروج من الحلقة؛continueتخطي ما تبقى من هذه الدورة
📝 تمارين
- الصعوبة ⭐: استخدم
forللتنقل عبر0..=10، مع عرض الأعداد الزوجية فقط (باستخدامif i % 2 == 0للتحقق). - الصعوبة ⭐⭐: قم بمحاكاة قيمة الإرجاع باستخدام
loop+break: ابحث عن أول قيمة أكبر من 6 في vec![1, 3, 5, 7, 9, 11] وأرجعها؛ وإذا لم يتم العثور على أي قيمة، فأرجع -1. - الصعوبة ⭐⭐⭐: استخدم حلقة
forذات الطبقتين لطباعة جدول الضرب 9×9، بحيث يتم تنسيق كل صف على أنه1x1=1 1x2=2 …. فكر في كيفية استخدام تسميات الحلقة للتحكم في منطق فواصل الأسطر.