Rust/ביטויים בוליאניים ותנאים/מתחילים

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי
Rust

כל תוכנת מחשב מקצועית יודעת כיצד להתמודד עם מצבים שונים ולהגיב להם בהתאם. למשל, כאשר אנחנו משתמשים בפלאפון שלנו, המעבד שלו יידע מה לעשות אם נלחץ על אפליקציה א' או אם נלחץ על אפליקציה ב'. בעצם, ניתן לומר שהמעבד מכוון להתמודד עם מצבים של "מה יקרה אם" וזהו הדבר הבסיסי המשותף העומד מאחורי כל התוכנות.

בשיעור זה נלמד על תנאים, שהם כלי בסיסי שקיים כמעט בכל שפת תכנות ומשמש לניתוב התוכנה ולבדיקה ולהערכה של משתנים. עוד נלמד על ביטויים בוליאניים שונים שהם אלו שעומדים בבסיסם של התנאים.

מבוא לתנאים[עריכה]

עד כה היינו מוגבלים מאוד ביכולותינו התכנותיות - כתבנו תוכניות שידעו לפעול רק בצורה זהה בכל פעם שהרצנו אותן לכל ערך אפשרי של משתנה ושלא ביצעו פעולות מיוחדות התלויות בערכו של המשתנה. למשל, יכולנו אמנם לחלק מספר בשתיים ולגלות בעצמנו שמדובר במספר זוגי, אבל לא יכולנו לומר למחשב באיזו דרך להגיב למידע החדש הזה, למשל אם להדפיס למשתמש הודעה מתאימה במידה שהמספר אכן זוגי או לא.

כדי לטפל במקרים כאלו נשתמש בתנאים שיאפשרו לנו לווסת את מהלך התוכנית. התנאים מאפשרים לנו להגדיר לתוכנית האם להפעיל או לא להפעיל פקודות מסיימות. נוכל למעשה לגרום לתוכנית "לקבל החלטות" בזמן ריצה, בהתאם למצבים אשר יכולים להשתנות מפעם לפעם. משפטי תנאי פשוטים מתחילים תמיד במילית "if" בצורה הבאה:

if (<condition>) {
<action>
}

אחרי ה-if, במקום בו רשום <condition>, נכתוב את התנאי עצמו - למשל אם x מספר זוגי או אם y גדול מעשר. כתיבת התנאי נעשית באמצעות ביטויים בוליאניים, אשר עליהם נרחיב בפרק הבא. אחרי הביטוי הבוליאני יבוא תמיד בלוק פותח ( '{' ) שמסמן למחשב את תחילת רצף הפעולות שהוא צריך לבצע אם התנאי אכן מתקיים.[1] אחרי הבלוק הפותח יבוא רצף של פעולות סטנדרטיות, כמו הדפסה באמצעות println!, או ביצוע פעולות אריתמטיות. פעולות אלו יתקיימו אך ורק אם התנאי יתקיים. לבסוף יבוא בלוק סוגר ( '}' ) שמסמן למחשב שהסתיים רצף הפעולות של התנאי.

כאשר המחשב נתקל בתנאי, הוא בודק אם הוא אכן מתקיים. אם התנאי מתקיים, המחשב יבצע את רצף הפעולות הכלול בבלוקים של התנאי. אם התנאי איננו מתקיים הוא ידלג על רצף הפעולות בבלוקים וייגש לביצוע הפעולה הבאה שנמצאת אחרי הבלוק הסוגר של התנאי.

נמחיש זאת בקצרה על ידי תרשים הזרימה הבא:

100%
100%

ביטויים בוליאניים[עריכה]

מה זה משתנה בוליאני?[עריכה]

ניזכר עתה בטיפוס של משתנה שהצגנו אותו קודם לכן אבל עד עתה לא ביצענו בו שימוש - טיפוס של משתנה בוליאני (bool). משתנה בוליאני הוא משתנה שיכול להכיל רק אחד משני ערכים - "אמת" (true) ו"שקר" (false).

משתנים בוליאניים חיוניים בעיקר לעבודה עם תנאים - לעתים יצטרך המחשב להכריע האם דבר הוא אמת או שקר, לדוגמה, האם נכון שערכו של המשתנה x הוא 6, או האם שקר הוא שערכו של המשתנה x קטן מערכו של המשתנה y. דרך ההצהרה על משתנה בוליאני זהה לדרך ההצהרה על משתנים פרימיטיביים אחרים:

let x: bool = true;

יחד עם זאת, לרוב לא נגדיר ידנית משתנה בוליאני כפי שאנחנו מגדירים משתנים רגילים באמצעות let, אלא במהלך הריצה של התוכנית נשתמש באופרטורים שונים שיחזירו לנו משתנה מטיפוס bool.

ביטויים בוליאניים - אופרטורים[עריכה]

כפי שציינו בשיעורים הקודמים, האופרטורים הם בדרך כלל סימנים מיוחדים (של תו בודד או מספר תווים) המהווים קיצורים לפונקציות בסיסיות. מטרתם של האופרטורים היא להקל על המתכנת בעת כתיבת קוד, כדי שלא יצטרך לקרוא לפונקציה ולשלוח לה ערכים.

כל האופרטורים מחזירים ערך מסוים לתוכנית. כך למשל, האופרטור "+", מהווה קיצור לפונקציה שסוכמת בין שני משתנים ומחזירה לתוכנית את תוצאת החיבור (הסכום). בפרק זה נכיר אופרטורים המשמשים ביטויים בוליאניים - כלומר סימנים מיוחדים בשפת ראסט המהווים קיצורים לפונקציות שמחזירות לתוכנית משתנה בוליאני.

אופרטור השוואה ("==")[עריכה]

נכיר עתה את האופרטור הבוליאני הנפוץ ביותר - אופרטור ההשוואה ("=="). אופרטור זה משמש להשוואת ערכים של שני משתנים. נמחיש עיקרון זה בדוגמה הבאה:

let x = 5;
let y = 10 - x; // y = 5
x == y; // true

ערכו של המשתנה x הוא 5 וגם ערכו של המשתנה y הוא 5. לכן, כשנשווה ביניהם בעזרת אופרטור ההשוואה נקבל שהתוצאה של השוואה שערכנו היא אמת (true), כלומר ערכו של x אכן שווה לערכו של y. להזכירכם, אופרטורים בוליאניים מחזירים תמיד ערך בוליאני ולכן התוצאה שתתקבל היא ערך בוליאני - אמת (true) או שקר (false). אם x ו-y היו שונים בערכים שלהם, היינו מקבלים תוצאת שקר (false).


מדוע משתמשים בשני סימני שווה ("==") לאופרטור ההשוואה ולא בסימן אחד?

התשובה לשאלה היא שכפי שלמדנו מקודם אופרטור של סימן שווה אחד ('=') משמש לביצוע פעולת השמה. בין שני האופרטורים יש הבדל מהותי וחשוב לשים אליו לב. אם במהלך קוד נכתוב x = y, אנחנו נשמור את הערך של y ב-x. לעומת זאת, אם במהלך קוד נכתוב x == y, אנחנו נשווה בין הערכים של שניהם ונקבל ערך בוליאני, אך לא נשמור את התוצאה ב-x.

אופרטור הבדלה ("=!")[עריכה]

נוסף על אופרטור ההשוואה, קיים גם אופרטור הבדלה ("=!"), כלומר אופרטור שמחזיר תוצאת אמת (true) אם הערך של שני משתנים שונה זה מזה. נסתכל בדוגמה הבאה:

let x = 7;
let y = 3
x != y; // true

בדוגמה האחרונה, הגדרנו משתנה בשם x שמאותחל למספר 7 ומשתנה נוסף בשם y שמאותחל למספר 3. בהמשך, השתמשנו באופרטור ההבדלה כדי לבדוק האם הערכים של x ו-y אכן שונים זה מזה. התוצאה של הביטוי היא כמובן אמת (true), וזאת משום שהמספר 7 אינו שווה למספר 3. אם למשל, היינו מנסים לבדוק האם הערכים של x ו-y בדוגמה הקודמת שונים זה מזה, היינו מקבלים תוצאת שקר (false), מכיון שהערכים של x ו-y היו שווים ל-5 ולכן אינם היו שונים זה מזה.


כדאי לדעת:

שני משתנים שהערכים שלהם שווים זה לזה, יחזירו בהכרח תוצאת שקר אם ננסה להבדיל ביניהם ושני משתנים שהערכים שלהם שונים זה מזה, יחזירו בהכרח תוצאת שקר אם ננסה להשוות אותם.

אופרטורי גודל ("<", ">", "=<", "=>")[עריכה]

בנוסף לאופרטורי ההשוואה וההבדלה, קיימים ארבעה אופרטורי גודל שעוזרים לנו להעריך מהו ההבדל היחסי בגודל בין הערכים של שני משתנים מטיפוס מספרי, כלומר האם המשתנה גדול ("<") מהמשתנה האחר, האם המשתנה קטן (">") מהמשתנה האחר, האם המשתנה גדול או שווה ("=<") למשתנה האחר והאם המשתנה קטן או שווה ("=>") למשתנה האחר. נסתכל למשל בדוגמה הבאה:

let x = 7;
let y = 3;
x > y; // true

גם כאן הגדרנו שני משתנים, x ו-y, ואתחלנו אותם בהתאמה לערכים 7 ו-3. אחרי כן, בדקנו בעזרת אופרטור גדול ("<") אם הערך של x גדול מהערך של y. מכיוון ש-7 אכן גדול מ-3, נקבל תוצאת אמת (true). יתר האופרטורים פועלים בצורה דומה.

כפי שוודאי שמתם לב, ארבעת האופרטורים נורא דומים זה לזה. כל אופרטור הוא תמונת ראי של אחר אופרטור אחר, הפוך ממנו במשמעותו. אז איך בעצם ניתן להבחין למשל בין גדול לקטן? התשובה לשאלה היא שבמבט ראשוני אמנם לא ניתן להבחין בין האופרטורים, אבל במידה וכבר נתקלתם בעבר בסימני גודל, סביר להניח שכשתשתמשו בהם בעת כתיבת קוד, הדבר ייראה לכם מאוד טבעי. אפשר גם לומר שהסימן שבוחרים לא משנה כל עוד מציבים ביטוי נכון, שכן הביטוי האם x גדול מ-y זהה במשמעותו לביטוי האם y קטן מ-x.

אופרטור השלילה ("!")[עריכה]

אופרטור נוסף החיוני לעבודה עם ביטויים בוליאניים הוא אופרטור השלילה ("!"). תפקידו של אופרטור זה הוא לשלול את האופרטורים האחרים ולהפוך את הערך של התוצאה המוחזרת - כלומר, אם למשל תוצאת ביטוי בוליאני מסוים החזירה תוצאת שקר, אז כשנצמיד לה את אופרטור השלילה, התוצאה תהפוך לתוצאת אמת. נמחיש עיקרון זה בעזרת הדוגמה הבאה:

let x = 7;
let y = 3;
x == y; // false
x ==! y; // true

כפי שתוכלו לראות בדוגמה, אנו מוסיפים את אופרטור השלילה ("!") רק אחרי האופרטור המקורי. לכן, אם נרצה לשלול את אופרטור ההשוואה ("=="), נוסיף לו סימן שאלה בסופו ונקבל "!==". משמעות השלילה במקרה זה היא לבדוק האם x אינו שווה בערכו ל-y, כלומר האם x שונה מ-y. אבל כבר נתקלנו באופרטור שבודק האם משתנה אחד שונה מהמשתנה השני, אז למה צריך אופרטור כזה? בעצם, בעבר לא היה קיים אופרטור להבדלה והדרך היחידה לבדוק שוני בין משתנים הייתה על ידי שלילת אופרטור ההשוואה. עם זאת, השימוש בשלילת האופרטור היה כל כך נפוץ, כך שהחליטו ליצור אופרטור עצמאי רק למקרה זה, שמוכר לנו כיום כאופרטור ההבדלה ("=!").

כמו שניתן לראות בדוגמאות למטה, ניתן לשלול כל אופרטור באמצעות אופרטור השלילה, גם את אופרטור ההבדלה. יותר מזה, ניתן להוסיף שלילת אופרטור גם על אופרטור השלילה.

x ==! y; //  x != y
x ==!! y; //  x == y
x ==!!! y; //  x != y

x !=! y; // x == y
x !=!! y; // x != y

x <! y; // x >= y
x <!! y; // x < y


ניתן גם לשלול תוצאה של ביטוי בוליאני (כלומר, להפוך את התוצאה) על ידי תחימת הביטוי כולו בסוגריים והקדמת אופרטור השלילה לסוגריים. למשל:

!(x == y); //  x != y


כדאי לדעת:

נקודה שהרבה מתכנתים מתחילים טועים בה היא שלילת אופרטורי גודל. האינטואיציה אומרת שאם נבדוק את הביטוי !< (כלומר האם משתנה אחד אינו גדול ממשתנה אחר) ונקבל תוצאת אמת, ודאי יחשבו זה אומר שבהכרח המשתנה השני קטן מן המשתנה הראשון. שימו לב, זו טעות! המשתנה השני לא חייב להיות קטן מהמשתנה הראשון - הוא יכול להיות גם שווה אליו. לכן, בניגוד לאינטואיציה, כשאנחנו שוללים אופרטורי גודל, איננו מקבלים את האופרטור ההפוך להם, אלא את האופרטור ההפוך בתוספת שווה. כלומר, אם x איננו קטן מ-y, אז הוא גדול שווה ל-y.

שילוב ביטויים בוליאניים בתנאים[עריכה]

ניתן לשמור את התוצאה שקיבלנו מביטוי בוליאני במשתנה. משתנה מסוג זה יהיה משתנה בוליאני.

let x = 5;
let y = 10 - x; // y = 5
let istrue = x == y; // istrue is a boolean variable

למשל, בדוגמה למעלה שמרנו, את התוצאה שקיבלנו מן הביטוי הבוליאני במשתנה istrue. אף על פי כן, כפי שאמרנו קודם, השימוש במשתנים בוליאניים איננו רווח. נהוג להציב את הביטויים הבוליאניים הישר בפעולת התנאי ולא לשמור אותם במשתנים. נחזור עתה למבנה הבסיסי של התנאי:

if (<condition>) {
	<action>
}

כעת, נבהיר אספקט נוסף שלא הסברנו מקודם על התנאי. המילית if צורכת אחריה תמיד ערך בוליאני של אמת או שקר - כלומר, לא יכול להגיע אחריה מספר כלשהו או תו, אלא רק ביטוי בוליאני. אם הערך שיבוא אחריה הוא אמת (true), המחשב יבצע את רצף הפעולות שבין הבלוקים של התנאי ואם הערך שיבוא אחריה הוא שקר (false), המחשב ידלג על רצף פעולות זה וימשיך מן הבלוק הסוגר האחרון. בעצם במקום בו רשום ה-<condition> נרשום את הביטוי הבוליאני שיפעיל את התנאי. נסתכל למשל על הדוגמה הבאה:

if (x > 3) {
	println!("{} is greater than 3", x);
}

כמו שתוכלו לראות, החלפנו בדוגמה הזאת הן את ה-<condition> והן את ה-<action>. כשהתוכנית תיתקל בתנאי מסוג זה היא תבדוק אם ערכו של x גדול מ-3. אם התוצאה של ביטוי זה תהיה אמת, יתבצע רצף הפעולות שבין הבלוקים ולכן תודפס למשתמש הודעה מתאימה. אם התוצאה של הביטוי יהיה שקר, אז המחשב ידלג על רצף הפעולות ולא יודפס למשתמש דבר.


כדאי לדעת:

בדומה לאופרטורי פעולות החשבון שניתן להשתמש בהם אך ורק על משתנים מאותו טיפוס, גם האופרטורים הבוליאניים דורשים שני משתנים מאותו הטיפוס. לכן, במידה ואנחנו רוצים לבצע פעולה בוליאנית לשני משתנים מטיפוסים שונים, נצטרך לבצע לאחד מהם הסבה.

אחרת ("else")[עריכה]

עד כה דיברנו על מקרה של תנאי פשוט. בדוגמה הקודמת, למדנו למשל איך לכתוב תכנית שבודקת אם משתנה גדול מ-3 ואם כן להדפיס הודעה מתאימה למשתמש. אבל מה אם אנחנו רוצים להדפיס גם הודעה מתאימה למשתמש במקרה שהמשתנה איננו גדול מ-3?

פתרון 1: שימוש בשני תנאים (לא יעיל)[עריכה]

תמיד אפשר להוסיף עוד תנאי שיבדוק את הדבר, כמו בדוגמה הבאה:

if (x > 3) {
	println!("{} is greater than 3", x);
}

if (x >! 3) {
	println!("{} is not greater than 3", x);
}

יחד עם זאת, לדוגמה זו מספר חסרונות; קודם כל, מבחינת יעילות, כבר בדקנו את האם x אכן גדול מ-3 וקיבלנו כבר את התשובה לכך. לכן, מיותר לבקש מהמחשב לבצע את אותה הבדיקה פעם נוספת. גם חבל לשמור את תוצאת הבדיקה לתוך משתנה אם אנחנו רוצים למנוע מהמחשב לצבע חישוב נוסף, משום שאכסון התשובה במשתנה תתפוס מקום בזיכרון של המחשב ומדובר במשתנה מיותר שאנחנו משתמשים בו רק פעם אחת. בנוסף לכל אלה, הקוד נראה כעת ארוך ומסורבל. על מנת להתמודד עם החסרונות של בדיקה חוזרת של הביטוי הבוליאני הומצאה המילית "else" - אחרת, עליה נלמד בפרק הבא.

פתרון 2: שימוש במילית "אחרת" ("else") - הפתרון העדיף[עריכה]

המילית else ("אחרת") משמשת אותנו לביצוע רצף של פעולות במקרה שהתנאי לא מתממש וזאת מבלי לחזור על חישוב התנאי כמו בדוגמה הקודמת. אם התנאי בכל זאת יתממש, רצף הפקודות של ה-else לא יבוצעו. כמו התנאי הפשוט (if), אחרי המילית else יבואו בלוק פותח ובלוק סוגר כדי להגדיר למחשב איזה רצף פעולות לבצע במקרה שהתנאי לא מתממש ואיפה לחזור לקוד הרגיל שיתממש ככה או ככה.

if (x > 3) {
	println!("{} is greater than 3", x);
}
else {
	println!("{} is not greater than 3", x);
}

שימו לב שבשונה מהתנאי הפשוט, שאחריו יבוא תמיד ביטוי בוליאני, אחרי המילית else יבוא בלוק פותח ולא יבוא תנאי בוליאני. הסיבה לכך היא שהמחשב כבר חישב את התוצאה של הביטוי הבוליאני קודם לכן, כשבדק את התנאי הפשוט ולכן אין צורך להזכיר לו במה מדובר. חשוב לציין גם שהמילית else לא יכולה לעמוד בפני עצמה - תמיד חייב לבוא תנאי לפניה כדי שניתן יהיה לדעת מהו האחרת. המילית else יכולה לבוא רק פעם אחת ברצף של תנאים ורק בסיומם. לא ייתכן מצב של תנאי if, תנאי else ואחריו תנאי if נוסף הרלוונטים לאותו רצף בלוקים.

אם אחרת ("else if")[עריכה]

ומה אם לפני שאנחנו רוצים להגיד לתוכנית מה לבצע אם התנאי לא מתקיים, אנחנו רוצים לומר לה לבדוק תנאי נוסף? למשל, אם כתבנו תוכנית שבודקת אם ערך של מספר מסויים הוא 5, ואם לא אנחנו רוצים לבדוק האם הערך של המספר הוא 6 ורק אז להדפיס הודעה מתאימה למשתמש. את זאת ניתן לבצע באמצעות רצף המיליות "else if", שפירושו אם אחרת.

if (x == 5) {
	println!("{} is 5", x);
}
else if (x == 6) {
	println!("{} is 6", x);
}

כפי שניתן לראות בדוגמה לעיל, התחביר של else if דומה בעיקרון לתחביר של if. אחרי else if יבוא תמיד אחרי ביטוי בוליאני כלשהו, כדי שהמחשב ידע איזה תנאי לבדוק ואחרי ביטוי זה יבואו בלוקים שיגדירו את רצף הפעולות שיבוצעו במידה שתנאי הזה אכן מתממש. כמו המילית else, גם תנאי ה-else if איננו עומד בפני עצמו ותמיד יבוא לפניו תנאי פשוט או תנאי else if אחר.


למה בעצם להשתמש ב-else if ולא ברצף של תנאי if פשוטים?

בוודאי עולה אצלכם השאלה מדוע כדאי לנו בכלל להשתמש ב-else if אם ניתן לעשות כמה תנאים פשוטים ברצף שיבדקו את הערך של המשתנה, על ידי שימוש רגיל במילית if. הסיבה לכך היא שב-else if טמון אספקט נוסף של יעילות שלא נראה למראית עין - else if כשמו מציין אם התרחש אחרת, כלומר, אם התנאי שלפניו לא מומש. לכן, התנאי של ה-else if ייבדק אך ורק אם התנאי שלפניו אכן לא מומש, שלא כמו בשימוש ב-if רגיל, שהתנאי ייבדק בכל מצב.

אמנם אם נשתמש ברצף של תנאי if, נוכל בסופו של דבר לקבל גם ככה את התוצאה הרצויה לנו, אבל המחשב יפעל בצורה לא יעילה ויבדוק את כל התנאים אחד אחרי השני גם אם תנאי אחד כבר התממש מקודם לכן. בניגוד לכך, כשיש רצף של תנאי else if, המחשב יפסיק את הבדיקה של הביטויים הבוליאניים אחרי שתנאי אחד ימומש ואז הוא ידלג לפעולה הבאה בקוד הנמצאת בסיום רצפי הבלוקים.

תנאים מורכבים[עריכה]

לעתים, נרצה לבדוק מספר תנאים כדי להריץ קטע קוד מסויים, למשל, האם x גדול מ-5 ובנוסף לכך, האם גם y גדול מ-10. בפעמים אחרות, נרצה להריץ קוד מסוים אם אחד משני תנאים מתקיים, למשל, האם x קטן משלוש או האם y גדול 7. לצורך מקרים אלו, נכיר עכשיו סוג נוסף של אופרטורים המשמשים אותנו בעת עבודה עם תנאים - אופרטורי "וגם" ("&&") ו"או" ("||").

שימו לב שאת כל אחד מהמקרים המצוינים לעיל ניתן לפתור גם בדרכים אחרות, למשל את המקרה הראשון ניתן לפתור באמצעות תנאי בתוך תנאי ואת המקרה השני ניתן לפתור באמצעות רצף של תנאים. יחד עם זאת, המטרה של פרק זה היא לייעל את הקוד ולקצר אותו, שכן קוד שיכלול תנאי בתוך תנאי יהיה קוד מסובך וקשה לקריאה וכן קוד ארוך שמבצע את אותו הדבר לאחד משני תנאים הוא קוד מתיש שמהווה חזרה מיותרת על רצף של פקודות.

אופרטור וגם ("&&")[עריכה]

אופרטור וגם ("&&") פועל על שני ביטויים בוליאניים ומחזיר בעצמו ביטוי בוליאני - true או false. לכן, תמיד יבואו לפניו ואחריו ביטויים בוליאניים. מטרתו של האופרטור היא לבדוק האם גם הביטוי הראשון וגם הביטוי השני מתממשים, כלומר האם כל אחד משני הביטויים יחזיר לנו תוצאת true. במידה ושני הביטויים אכן יתממשו, תוחזר למשתמש תוחזר למשתמש תוצאת true ובמידה ואחת מהביטויים איננו מתממש, תוחזר למשתמש תוצאת false. נדגים את דרך הפעולה האופרטור בדוגמה הבאה:

if ((x < 3) && (y > 5)) {
	println!("{} is greather than {}", y, x);
}

בדוגמה למעלה עשינו שימוש בתנאי מורכב ובאופרטור וגם - בדקנו האם גם x קטן מ-3 וגם y גדול מ-5. שימו לב שהסוגריים נכתבו רק לשם הנוחות, ואין צורך לכתוב אותם. אם במהלך התוכנית שלנו שני התנאים הללו היו מתממשים, היינו מקבלים תוצאת true ואז היינו נכנסים לתוך רצף הפקודות של התנאי. אם היינו מקבלים תוצאת false, בלומר שני התנאים לא התממשו, היינו ממשיכים לרצף הפקודות הבא בקוד שאחרי הבלוקים.

כאמור, אופרטור וגם זקוק לכך שגם הביטוי הבוליאני שבא לפניו וגם הביטוי שיבוא אחריו יחזירו לו תוצאת true. לעתים ניתן לחשב את התוצאה שיחזיר לנו האופרטור רק מתוצאת הביטוי הראשון - אם כאשר יחשב האופרטור את תוצאת הביטוי הראשון הוא יקבל תוצאת false, הוא לא ימשיך לחשב את תוצאת הביטוי השני וזאת מפני שהתוצאה תהיה false לא משנה מה הייתה התוצאה של הביטוי השני. זכרו שהאופרטור מחזיר תוצאת true רק אם שני הביטויים שלפניו יחזירו תוצאת true. לכן גם אם תוצאת הביטוי השני הייתה true, זה כבר לא משנה לו, כי תוצאת הביטוי הראשון הייתה false ולכן אין צורך לבדוק את הביטוי השני.

אופרטור או ("||")[עריכה]

בפרק האחרון הכרנו את אופרטור וגם, שמקבל שני ביטויים בוליאניים ואמרנו שאם תוצאת הביטוי הראשון היא false, המחשב לא ימשיך לבדוק את תוצאת הביטוי השני. אוםרטור או ("||"), האופרטור המנוגד לאופרטור וגם, מקבל גם הוא שני ביטויים בוליאניים ומחזיר גם הוא תוצאה בוליאנית של true או false. בניגוד לאופרטור וגם שזקוק לכך ששני הביטויים הבוליאניים שלו יתממשו, אופרטור או זקוק לכך שרק אחד משני הביטויים יתממש כדי לפעול. נמחיש עיקרון זה בדוגמה הבאה:

if ((x > 3) || (x < 3)) {
	println!("{} is not 3", x);
}

בדוגמה מעל בדקנו האם x גדול מ-3 או האם x קטן מ-3, שזה בדיוק כמו לבדוק האם x איננו שווה ל-3. אם אחד משני התנאים הללו התממש, כלומר x אכן גדול מ-3 או x אכן קטן מ-3, ייכנס המחשב לרצף הפעולות של התנאי. שימו לב שהשימוש באופרטור או דומה לשימוש ב-else if. כמו בעבודה עם תנאי else if, אם הביטוי הבוליאני הראשון יתממש, לא יהיה צורך לבדוק את הביטוי הבוליאני השני והמחשב ייכנס לתוך התנאי ויריץ את רצף הפעולות שבו. אם הביטוי הבוליאני הראשון לא התממש, כלומר החזיר תוצאת false, יבדוק המחשב את תוצאת הביטוי השני ובמידה והיא true, ייכנס לרצף הפעולות של התנאי.

match[עריכה]

כלי נוסף המשמש לבקרה ולהערכה של תנאים הוא המילית match, המאפשרת לנו להחליף רצף ארוך של תנאי else if בקטע קוד קצר ופשוט. בניגוד לתנאי else if רגילים שבעזרתם אנו יכולים לבדוק ביטויים בוליאניים שונים, באמצעות match אנחנו יכולים לבדוק אך ורק ביטויי השוואה. אחרי המילית match יבוא בדרך כלל משתנה, אותו נרצה להשוות עם מספר של ערכים אחרים ואחריו יבוא בלוק שיגדיר את רצף הפקודות שיבוצעו. נתסכל על דוגמת הקוד הבאה:

let x = 3;
match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    4 => println!("four"),
    5 => println!("five"),
    _ => println!("something else"),
}

בדוגמת הקוד האחרונה ערכנו השוואה לערך של x. המספרים בתוך הבלוקים מציינים את הערכים השונים עמם השוונו את x (במקרה זה המספרים 1-5). אחרי כל מספר באה המחרוזת "<=" והיא מציינת למחשב שאחריה יבוא רצף של פעולות אותו הוא יצטרך לבצע אם התוצאה של ההשוואה שערכנו היא אמת. במקרה זה, מכיוון שערכו של המשתנה x הוא 3, תודפס למחשב המחרוזת "three". שימו לב שבשונה ממה שאנחנו מכירים, בסיום רצף הפעולות יבוא פסיק (',') ולא נקודה פסיק. הסיבה לכך תובהר בהמשך. כמו במשפטי else if, בשל העובדה שאחד התנאים התממש, בסוף רצף הפעולות המחשב לא ימשיך לבדוק את יתר התנאים אלא ייצא מן התנאי ויחזור לקוד הרגיל.

דבר נוסף שיש להבהיר על תנאי match הוא שאחרי המחרוזת "<=" תבוא רק פעולה אחת. אם נרצה לבצע יותר מפעולה אחת נצטרך להשתמש בבלוקים. שימו לב שכאן רצף הפעולות בקוד נוהג כרגיל ואחרי כל פעולה תבוא נקודה פסיק. יחד עם זאת, בסופו של הבלוק עדיין יבוא גם פסיק רגיל.

let x = 3;
match x {
	3 => {
		println!("three\n");
		println!("שלוש");
		},
	_ => println!("something else"),
}

ודאי שמתם לב שבשתי הדוגמאות הופיע גם קו תחתון ('_') שלא התייחסנו אליו עד עכשיו ותהיתם מדוע הוא שם. התשובה לכך היא שהקו התחתון משמש למקרה שאף תנאי לא התממש, בדומה למילית else כשהיא באה לבדה. אם אף תנאי לא התממש, תבוצע הפעולה שתבוא אחרי הקו התחתון. אבל למה בעצם לא הסרנו את הקו בדוגמה האחרונה? התשובה לכך היא שלא ניתן להסיר את הקו התחתון גם אם אין צורך בו. כפי שנלמד בהמשך, המילית match היא כלי חזק שמשמש לביצוע של פעולות מורכבות בשפת ראסט ולכן אם נסיר את הקו התחתון נקבל שגיאת קומפילציה שאומרת שלא כיסינו את כל המקרים האפשריים. אם אתם בכל זאת רוצים להשתמש ב-match אבל אתם לא רוצים שיבוצע דבר במקרה שאף תנאי לא יתממש, אתם יכולים להוסיף סוגריים () אחרי הקו התחתון. הסוגריים יתנו את אותו אפקט כאילו לא בוצעה אף פעולה.

let x = 3;
match x {
    3 => println!("three"),
	_ => (),
}

תרגול[עריכה]

לפני שתעברו לשיעור הבא, מומלץ מאוד לגשת לעמוד התרגול של השיעור. התרגילים של שיעור זה עוסקים בכתיבת תנאים פשוטים ומורכבים. כאמור, התנאים הם מהכלים הבסיסיים ביותר ונשתמש בהם רבות גם בהמשך. אמנם בשיעור הבא נעסוק בנושא אחר אך גם הבנתו כרוכה בהבנה מלאה של יסודות התנאי. בהצלחה!

Rust
  1. ^ וזאת בניגוד לחלק משפות התכנות שמאפשרות כתיבת תנאי החל על שורת קוד אחת ללא תיחום התנאי באמצעות בלוקים.