دوستدار نرمافزار، فلسفه و ادبیات. وب سایت:http://www.alihoseiny.ir
آموزش زبان برنامهنویسی Rust - قسمت5: حلقه ها + تمرین
حالا که در جلسهی قبلی با دستور شرطی if
آشنا شدیم, وقت آن است که سراغ حلقهها برویم تا از این به بعد بتوانیم با هم برنامههای واقعی بنویسیم.
راستی یک خبر خوب. از این به بعد اکثر جلسات شامل یک یا چند تمرین میشوند تا سریعتر و بهتر بتوانیم زبان Rust را با هم یاد بگیریم.
برای این دوره یک repository در گیتهاب ساختهام که با کلیک روی این نوشته میتوانید به آن دسترسی داشته باشید. در این repository پاسخ تمرینها و نمونه کدهای این دورهی آموزشی قرار دارند.
خب برویم سراغ حلقهها.
ما خیلی وقتها نیاز داریم که یک قطعه کدرا چند بار اجرا کنیم. برای همین هم در زبانهای برنامهنویسی مختلف, دستورات تکرار مختلفی ساخته شده است.
خیلی از زبانها سه حلقهی for, while و do while را پشتیبانی میکنند. امّا در Rust حلقهای مثل do while وجود ندارد.
به جای آن ما 3 نوع حلقه در Rust داریم: loop, for و while (مثل زبان VHDL).
حالا هر کدام از این حلقههارا با هم بررسی میکنیم.
حلقه loop
همین دستور پیادهسازی کنید(یکی از کارهایی که در تمرینهای این جلسه انجام میدهیم).
حلقهی loop شرطی نمیگیرد. یعنی این حلقه تا ابد اجرا میشود.
مثلاً اگر کد زیر را اجرا کنید, تا زمانی که ctrl+c
را فشار ندهید برنامه به چاپ کردن مقدارش ادامه میدهد(اخطار: این برنامه ممکن است موجب هنگ کردن دستگاهتان شود. لطفاً با رعایت نکات ایمنی و با کمک بزرگترها آنرا اجرا کنید)
fn main() {
loop {
println!("همینطوری اینرو پرینت میکنه...");
}
}
دستور break
حالا شاید بپرسید که چطوری میشود این حلقهرا متوقّف کرد؟ پاسخ ساده است: با گذاشتن دستور break
.
هروقت که جریان اجرای برنامه به دستور break
برسد, اجرای حلقه متوقّف میشود و کنترل برنامه به دستورات بعد از حلقه منتقل میشود.
دستور break
یک قابلیّت دیگر هم دارد. شما میتوانید با این دستور مقداری را خروجی بدهید.
مثلاً کد زیر را ببینید:
fn main() {
let mut counter = 0;
let a = loop {
if counter == 5 {
break counter;
}
counter += 1;
};
println!("a = {}", a);
}
در این برنامه اوّل از همه یک متغیّر mutable به نام counter
تعریف کردیم تا تعداد تکرارهای حلقهرا با آن کنترل کنیم.
بعد از آن یک متغیّر دیگر به نام a
تعریف کردیم. امّا به جای مقداردهی مستقیم به آن, مقدارش را برابر خروجی حلقهی مقابلش قرار دادیم.
ابتدای حلقه با یک دستور if
میبینیم که آیا مقدار counter
به 5 رسیده است یا نه. اگر رسیده بود, با استفاده از دستور break
مقدار متغیّر conter
را بر میگردانیم.
یعنی هروقت counter
برابر با 5 شود ما مقدار a
را برابر با آن قرار میدهیم.
اگر counter
برابر با 5 نبود, مقدارشرا یک واحد افزایش میدهیم.
در این کد ۲ نکته وجود دارد که باید خوب به آن توجّه کنید:
۱-بعد از دستور if
از else
استفاده نکردیم. چون هروقت که شرط if
برقرار شود دیگر از حلقه خارج میشویم و مطمئن هستیم که کدهای حالت else
اجرا نمیشوند.
۲-بعد از بستن براکت loop
باید ;
بگذاریم. چون در غیر این صورت کامپایلر نمیفهمد که این statement تمام شده است.
نکتهی کنکوری: از این دستور میتوان در حلقههای for
و while
هم برای متوقّف کردن و خروج از حلقه استفاده کرد. امّا نمیتوان با آن مقدار برگرداند.
حلقه loop چه کاربردی دارد؟
حلقهی loop
کاربردهای فراوانی دارد. مثلاً میخواهیم منتظر بمانیم تا یک thread کارش تمام شود یا پاسخی از سرور دریافت کنیم.
اگر شرایط سرراست نباشد, استفاده از حلقهی loop و بررسی وضعیت درون آن بهترین راه است.
حلقه while
اینکه یک حلقهرا تا زمانی که یک شرط برقرار است تکرار کنیم اتّفاق خیلی خیلی رایجی است. برای همین برای این الگو در زبان Rust یک حلقهی جداگانه داریم.
الگوی کلّی دستور while
به شکل زیر است:
while condition {
// do something
}
تا زمانی که شرط حلقه (condition) درست باشد, حلقه تکرار میشود. مثلاً حلقهی زیر تا زمانی که مقدار متغیّر a مضرب 10 نباشد به چاپ کردن آن ادامه میدهد:
fn main() {
let mut a = 1;
while a % 10 != 0 {
println!("a= {}", a);
a += 1;
}
}
حلقه for
خب حالا فرض کنید که ما حلقهای میخواهیم که از عدد ۲ تا ۱۰ را بشمارد و یک تکّه کد را با توجّه به آن اجرا کند.
اگر بخواهیم این کار را با while
انجام بدهیم, احتمال رخ دادن ارور خیلی زیاد است.
مثلاً فرض کنید که یادمان برود condition حلقه while
را داخل آن آپدیت کنیم. در این صورت یک حلقهی بینهایت بهوجود میآید که دستگاه شما را به خاطر مصرف بیش از اندازهی منابع به فنا میدهد.
اینجا پای حلقهی for وسط میآید. همین مثالی که زدم را درنظر بگیرید. میشود کد زیر:
fn main() {
for counter in 2..11 {
println!("counter = {}", counter);
}
}
خروجی این کد میشود این:
counter = 2
counter = 3
counter = 4
counter = 5
counter = 6
counter = 7
counter = 8
counter = 9
counter = 10
حالا کدی که نوشتیم یعنی چی؟ بگذارید حالت کلّی حلقهی for
را بررسی کنیم:
for counter in range {
// your code
}
حلقهی for با کلمهی کلیدی for
شروع میشود. پس از این کلمهی کلیدی نام شمارندهی حلقه میآید. (حواستان باشد که شما نمیتوانید مقدار شمارندهرا داخل بدنهی حلقه تغییر بدهید, چون یک متغیّر immutable است).
بعد از شمارنده کلمهی کلیدی in
میآید. کلمهای که بعد از آن range حلقه قرار میگیرد.
درمورد range بعداً به صورت مفصّل صحبت میکنیم.
الان فقط کافی است که بدانید وقتی میخواهیم بگوییم که حلقه از عدد m شروع شود و به عدد n ختم شود, از مقدار زیر به عنوان range استفاده میکنیم:
m..n+1
توجّه کنید که وقتی که میخواهیم مثلاً تا عدد 10 را بشماریم, باید حد بالایی range را برابر با 11 قرار بدهیم.
پیمایش مجموعهها با حلقهی for
یکم اسم فارسیاش سخت شد. یعنی میخواهیم با یک حلقهی for روی تک تک عناصر یک مجموعه(مثلاً یک آرایه) حلقه بزنیم و روی هرکدام یک کد را اجرا کنیم.
مثلاً فرض کنید میخواهیم عناصر یک آرایهرا پرینت کنیم. در حالت عادی کد زیر را میزنیم:
fn main() {
let my_array: [i32;5] = [1,2,3,4,5];
for counter in (0..5){
println!("current element= {}", my_array[counter]);
}
}
این برنامه خروجی زیر را میدهد:
current element= 1
current element= 2
current element= 3
current element= 4
current element= 5
خب این روش کار میکند, امّا راه حل خیلی خوبی نیست. ممکن است range را اشتباه وارد کنیم و به خاطر درست نبودن index آرایه به ارور بخوریم.
همچنین هربار که میخواهیم به عنصر فعلی اشاره کنیم باید تمامی عبارت: my_array[counter]
را به کار ببریم. اتّفاقی که در برنامههای واقعی اذیت کننده است.
Rust برای این کار راه حل خیلی سادهتری دارد. یک نگاهی به کد زیر بیاندازید تا توضیح بدهم:
fn main() {
let my_array: [i32;5] = [1,2,3,4,5];
for element in my_array.iter(){
println!("current element = {}", element);
}
}
تفاوتش را فهمیدید؟ به جای اینکه روی یک range حلقه بزنیم, روی خود آرایه این کار را کردیم.
همه چیز مثل قبل است, به جز اینکه به جای نوشتن range نام آرایه را مینویسیم و آخرش ()iter.
اضافه میکنیم.
حالا element به جای اینکه مقدار عددی فعلی در range باشد, خود عنصر فعلی در آرایه است.
اینطوری هم مطمئن هستیم که با index به مشکل نمیخوریم و هم راحتتر به عنصر آرایه دسترسی پیدا میکنیم.
شما میتوانید نسخهی ویدیویی این آموزش را اینجا ببینید:
خب حالا برویم سراغ تمرینها:
تمرین
این تمرینها همان تمرینهای رایج یادگیری برنامهنویسی هستند که به نظرم ارزش اینکه یک بار با Rust هم آنها را امتحان کنیم دارند.
۱-حلقهی while را با حلقهی loop پیادهسازی کنید
۲-شکل زیر را با استفاده از حلقهی for چاپ کنید:
// You should print below pattern.
*
**
***
****
*****
****
***
**
*
رفتن به اوّلین قسمت مجموعه رایگان آموزش زبان برنامه نویسی Rust
مطلبی دیگر از این انتشارات
نصب و کانفیگ VirtualEnv و VirtualEnvWrapper
مطلبی دیگر از این انتشارات
آموزش زبان برنامهنویسی Rust – قسمت۸: Borrowing
مطلبی دیگر از این انتشارات
چرا به یک کتابخانهی دیگر برای انگولار احتیاج داشتیم؟