Rust/לולאות/מתחילים: הבדלים בין גרסאות בדף

תוכן שנמחק תוכן שנוסף
Steeve815 (שיחה | תרומות)
מ הוספת קטגוריה:Rust באמצעות HotCat
Steeve815 (שיחה | תרומות)
עדכון: <source> → <syntaxhighlight>
 
שורה 6:
== הצורך בלולאות ==
יתכן שבמהלך תוכנית שנכתוב נרצה שהמחשב יבצע את אותה הפעולה מספר פעמים. למשל, יתכן שנרצה שהמחשב ידפיס למשתמש את המחרוזת "שלום עולם" במשך 5 פעמים. כיצד נגרום לו לעשות זאת? ניתן לשכפל את פקודת ההדפסה במשך 5 פעמים, כמו בדוגמה הבאה:
<sourcesyntaxhighlight lang = "rust">
fn main()
{
שורה 19:
println!("Hello, world!\n");
}
</syntaxhighlight>
</source>
 
פתרון זה הוא פתרון מאוד מעניין, אבל יש בו המון חסרונות. מה אם למשל היינו רוצים לשכפל את הקוד לא 5 פעמים אלא 100 פעמים? האם היינו עוברים ומעתיקים הפקודה פעם אחר פעם במשך 100 פעמים?אולי חלק יאמרו ששכפול הקוד 100 פעמים אינו מוגזם, אבל מה אם נרצה להדפיס את ההודעה 1000 פעמים או 10000 פעמים?
שורה 30:
הלולאה הפשוטה ביותר בשפת ראסט היא לולאת loop שפועלת אין סוף פעמים. כמו שכבר ראינו במקומות אחרים, גם רצף הפעולות של הלולאה מוגדר באמצעות בלוקים. תחילה תבוא המילית loop שמסמלת לקומפיילר שבחרנו להשתמש בלולאת loop ואחריה יבוא רצף פעולות מסויים, עליו תחזור הלולאה במשך אין ספור פעמים. כל ריצה או חזרה של הלולאה על רצף הפעולות בתוך הבלוק מכונה "'''איטרציה'''".
 
<sourcesyntaxhighlight lang = "rust">
loop {
println!("Hello, world!\n");
שורה 37:
println!("The computer will never print this line!");
 
</syntaxhighlight>
</source>
מרגע היכנסו ללולאה, המחשב יבצע פקודה אחר פקודה בלולאה, לפי הסדר בו הפקודות נכתבו בקוד וכשיגיע לבלוק הסוגר, יחזור לתחילת הלולאה ויתחיל לבצע את אותן הפעולות שוב ולפי אותו הסדר. מכיוון שהלולאה loop היא לולאה אינסופית, המחשב לעולם לא יצא מן הלולאה ולכן קטע קוד שייכתב אחרי הלולאה לעולם לא יתבצע. בדוגמה האחרונה, המחשב ידפיס את המחרוזת "Hello, world!" אינסוף פעמים ולכן לעולם לא יגיע לביטוי שאחרי הבלוק הסוגר של הלולאה ולעולם לא ידפיס אותו.
 
== הוראת break לשבירת הלולאה ==
אבל אם אנחנו רוצים להדפיס למשתמש רק 5 פעמים את המחרוזת "Hello, world!", כיצד נעשה זאת? הרי ראינו שהלולאה הקודמת רצה במשך אינספור פעמים. לשם כך, הומצאה הוראת "break" ש"שוברת" את הלולאה. בעצם הוראה זו, נותנת למחשב פקודה להפסיק לבצע את הפעולות שבתוך הלולאה ולחזור לבצע את הפעולות שאחרי בלוק הסיום של הלולאה. נסתכל למשל בדוגמת הקוד הבאה:
<sourcesyntaxhighlight lang = "rust">
loop {
println!("Hello, world!\n");
שורה 50:
 
println!("The computer will print this line!");
</syntaxhighlight>
</source>
בדוגמה האחרונה, המחשב ידפיס פעם אחת את המחרוזת "Hello, world!". אחרי כן, כשייתקל בהוראת break, הוא ייצא מן הלולאה ויחזור לרצף הפקודות שמופיע אחרי הבלוק הסוגר. יציאתו של המחשב מן הלולאה גורמת לכך שמעתה ואילך אף לא פקודה אחת שנכתבה בתוך הלולאה תתבצע, גם הפקודות שעדיין לא התבצעו אפילו פעם אחת. לכן, המחשב לעולם לא יגיע לפקודה שנמצאת אחרי ה-break ולעולם לא תודפס שורה זו. לעומת זאת, בשל שבירת הלולאה, השורה שנמצאת אחרי הבלוק הסוגר של הלולאה אכן תתבצע ולכן ההודעה שם אכן תודפס.
 
שורה 56:
;אז איך נוכל להדפיס את המחרוזת "Hello, world!" במשך 5 פעמים בלבד?
כדי לעשות זאת נוסיף ללולאה תנאי שיבדוק את מספר האיטרציות של הלולאה. לשם כך, ניצור משתנה, אותו נעלה בכל איטרציה של הלולאה באחד. אחרי כן, נבדוק בעזרת תנאי פשוט האם ערכו של המשתנה כבר הגיע ל-5 ואם התוצאה תהיה אמת, נשבור את הלולאה ונצא ממנה.
<sourcesyntaxhighlight lang = "rust">
let mut i = 0;
loop {
שורה 67:
}
}
</syntaxhighlight>
</source>
 
{{משימה|נסו בעזרת לולאת loop והוראת break להדפיס את כל המספרים הטבעיים מ-1 עד 10. ודאו שאינכם מדפיסים מספרים הגדולים מעשר. רמז: צרו משתנה אותו תעלו בכל איטרציה של הלולאה באחד והדפיסו את תוכנו.}}
שורה 76:
המבנה של לולאת while דומה לזה של תנאי פשוט. תחילה תבוא המילית while ואחריה יבוא תמיד ביטוי בוליאני כלשהו, שתוצאתו יכולה להיות אמת או שקר. אחרי הביטוי יבוא בלוק שיגדיר את רצף הפעולות שיבוצע אם התנאי החזיר תוצאת אמת. נתסכל למשל על הדוגמה הבאה:
 
<sourcesyntaxhighlight lang = "rust">
let mut x = 1;
while x <= 10 {
שורה 82:
x+=1;
}
</syntaxhighlight>
</source>
 
בעת שמחשב יתקל בלולאת while, הוא יבדוק את התנאי שעומד בבסיסה. במקרה שלנו המחשב יבדוק האם x קטן שווה ל-10. מאחר שתוצאת ביטוי זה היא אמת, ייכנס המחשב ללולאה ויבצע את רצף הפעולות שבתוכה. בסיום כל איטרציה של הלולאה, יבדוק המחשב את התנאי מחדש. אם התוצאה שלו תהיה עדיין אמת, יבצע שוב את רצף הפעולות של הלולאה. בדוגמה שלמעלה גרמנו למחשב להדפיס את כל המספרים הטבעיים בין 1- ל-10.
שורה 88:
המחשב ייכנס ללולאה אך ורק אם התנאי שעומד בבסיסה יתממש. בדוגמה הבאה, המחשב לא ידפיס כלום, מכיוון שהתנאי שעומד בבסיס הלולאה יחזיר תוצאה שקר ולכן המחשב בכלל לא ייכנס ללולאה.
 
<sourcesyntaxhighlight lang = "rust">
// print all the negative numbers from x to 0
let mut x = 1;
שורה 95:
x+=1;
}
</syntaxhighlight>
</source>
{{הארה|למרות שאת כל מה שנרצה לעשות עם לולאת while ניתן גם לעשות עם לולאת loop והוראת break, השימוש בלולאת while הרבה יותר נוח ורווח בקרב מתכנתים. קוד המשתמש בלולאת loop שלא בשביל פעולה אינסופית נחשב לקוד מסורבל ולכן, כשנרצה לכתוב קוד המשלב בתוכו לולאה שאינה אינסופית, נעדיף להשתמש בלולאת while.}}
 
שורה 103:
המבנה של לולאות for שונה מזה של לולאות loop ו-while שנתקלו בהן עד עתה. תחילה תבוא המילית for שמציינת את סוג הלולאה ואחריה יבוא משתנה לבחירתו של המשתמש. אחרי המשתנה, תבוא תמיד המילית "in" ואחריה יבוא טווח מסוים של ערכים (משתנים). בדוגמאות הבאות נעסוק בטווח של מספרים. אחרי כן, יבוא הבלוק שיגדיר את רצף הפעולות של הלולאה. נסתכל על המבנה הבסיסי של לולאות for בדוגמה הבאה:
 
<sourcesyntaxhighlight lang = "rust">
for <variable> in <range> {
<action>
}
</syntaxhighlight>
</source>
 
=== טווח הערכים של לולאות for ===
שורה 116:
בשפת ראסט, טווח של ערכים מסומן על ידי שתי נקודות (' '''..''' ').
 
<sourcesyntaxhighlight lang = "rust">
for x in 1..101 {
<action>
}
</syntaxhighlight>
</source>
 
בדוגמה מעל, הלולאה תחלוף על כל המספרים בטווח שבין 1-101, לא כולל המספר 101. לכן, אם נבקש מהלולאה להדפיס לנו את כל המספרים שבטווח זה, היא לא תדפיס לנו את המספר 101.
שורה 126:
אם בכל זאת נרצה שהלולאה תתייחס גם למספר 101, נוכל להוסיף '=' בסוף הטווח, כך שנקבל (' '''=..''' ') ובזאת לסמן לקומפיילר להתייחס גם לקצה הנגדי של הטווח. לדוגמה:
 
<sourcesyntaxhighlight lang = "rust">
for x in 1..=101 {
<action>
}
</syntaxhighlight>
</source>
 
=== המשתנה העומד בבסיס הלולאה ===
שורה 137:
המשתנה העומד בבסיס הלולאה יכיל בכל איטרציה ערך מתוך טווח הערכים של הלולאה. במקרה שלנו הערך הזה יהיה מספרי. באיטרציה הבאה של הלולאה, המשתנה יכיל את הערך הבא הנמצא בטווח - במקרה שלנו, המספר העוקב למספר הקודם. למעשה, לולאות for פועלות כך שבאיטרציה הראשונה של הלולאה, יכיל המשתנה את האיבר שנמצא במקום הראשון בטווח הערכים של הלולאה. באיטרציה השנייה של הלולאה, את האיבר שנמצא במקום השני, וכן הלאה. נסתכל למשל בדוגמה הבאה:
 
<sourcesyntaxhighlight lang = "rust">
for x in 1..101 {
println!("{}\n", x);
}
</syntaxhighlight>
</source>
 
בדוגמה שלפנינו יש לולאת for המדפיסה את כל המספרים בין 1-ל-100. טווח הלולאה הוא בין המספרים 1-101 (לא כולל 101) והלולאה חולפת מספר אחרי מספר ומדפיסה אותו. באיטרציה הראשונה של הלולאה, המספר הראשון שיודפס יהיה 1, משום שהמספר 1 הוא המספר הראשון בטווח הערכים של הלולאה לכן ערכו של x יהיה אחד. באיטרציה השנייה יודפס המספר 2, בשלישית 3, וכן הלאה.
שורה 150:
כאמור, המשתנה העומד בבסיס הלולאה הוא משתנה מאוד ייחודי. אחת התכונות המיוחדות של משתנה זה היא שאין צורך להצהיר עליו כמו שאנחנו מצהירים על משתנה רגיל לפני הכניסה ללולאה. ההצהרה על המשתנה מתבצעת על ידי המילית for ולכן אין צורך להצהיר עליו כמו על משתנה רגיל באמצעות let. כשאנחנו מוסיפים לקוד לולאת for ובתוכה משתנה, אנחנו כמו מצהירים עליו בתוך רצף הפעולות של הלולאה:
 
<sourcesyntaxhighlight lang = "rust">
{
let x = num;
}
</syntaxhighlight>
</source>
 
לכן, אורך החיים של המשתנה העומד בבסיס הלולאה מוגדר רק בתוך הבלוק של רצף הפעולות של הלולאה. ברגע שנצא מן הלולאה, לא נוכל להשתמש עוד בערכו של המשתנה:
<sourcesyntaxhighlight lang = "rust">
for x in 5..10 {
println!("{}\n", x);
}
println!("{}\n", x); // x is not found in this scope
</syntaxhighlight>
</source>
 
כמו כל משתנה אחר, המשתנה העומד בבסיס הלולאה מוגדר כ-immutable ולכן, אם נרצה לבצע לו השמה, נצטרך להוסיף את המילית "mut" להצהרה על המשתנה אחרי ה-for. שימו לב שברוב המקרים נשאיר את המשתנה העומד בבסיס הלולאה בתור immutable מפני שסביר להניח שלא נצטרך לבצע לו פעולת השמה - ערכו של המשתנה משתנה בכל איטרציה של הלולאה ולא נשמר בסופה ולכן נדיר שנצטרך לאחסן בו ערך ולשמור אותו. למשל:
 
<sourcesyntaxhighlight lang = "rust">
for mut x in 0..10 {
x += 1;
println!("{}\n", x); // we could just send (x + 1) instead of making x mutable
}
</syntaxhighlight>
</source>
 
=== היפוך טווח המספרים בלולאה ===
שורה 180:
;אז איך כן הופכים את סדר ההדפסה של המספרים בעזרת לולאת for?
ניתן להשתמש בפונקציית .rev() (קיצור של reverse - היפוך) שמבצעת היפוך לסדר הפעולה של הלולאה. פונקציה זו גורמת לכך שבאיטרציה הראשונה של הלולאה, הערך של המשתנה העומד בבסיס יהיה כערך האיבר האחרון הכלול בטווח, באיטרציה השנייה כערך האיבר הלפני-אחרון וכו'. כדי להשתמש בפונקציית rev(), יש לעטוף את טווח הלולאה בסוגריים ולהוסיף אחריהם את הפונקציה בעזרת נקודה:
<sourcesyntaxhighlight lang = "rust">
for x in (1..=10).rev() {
println!("{}\n", x);
}
</syntaxhighlight>
</source>
 
== לולאה מקוננת ==
לעתים אנו נצטרך להגדיר שתי לולאות במהלך התוכנית שלנו, כאשר אחת תהיה כלולה בתוך השנייה. למשל, אם נרצה לכתוב תוכנית שעוברת על טבלה המחולקת לטורים ושורות, נצטרך שתי לולאות - אחת שתעבור על השורות ואחת שתעבור על הטורים. לולאה שמוגדרת בתוך לולאה אחרת נקראת "'''לולאה מקוננת'''". נציג עתה דוגמה למקרה בו נזדקק ללולאה מקוננת:
 
<sourcesyntaxhighlight lang = "rust">
fn main()
{
שורה 207:
}
}
</syntaxhighlight>
</source>
 
{{משימה|הדפיסו את לוח הכפל בעזרת שתי לולאות for. שימו לב שבניגוד לדוגמה מעל אינכם זקוקים למשתנה מסוג mutable!}}