# אופרטורים Perl מאיית את האופרטורים הבוליאניים פעמיים, בשתי מחלקות קדימות שונות. הצורות הסימבוליות בסגנון C (`&&`, `||`, `!`) נקשרות חזק; צורות המילה (`and`, `or`, `not`) נקשרות רפה מאוד. קיים גם `//` עבור הניב *defined-or*, `xor` עבור או־בלעדי, והשילוש `?:` שהוא בחירה לוגית בתחפושת. ## המצאי המלא | אופרטור | נקרא | מחזיר | קדימות | |-----------|------------|----------------------------------------|------------| | `!` | not | `1` מנורמל או מחרוזת ריקה | גבוהה | | `&&` | and | שמאל אם שקר, אחרת ימין (ה־ *אופרנד*) | גבוהה | | `||` | or | שמאל אם אמת, אחרת ימין (ה־ *אופרנד*) | גבוהה | | `//` | defined-or | שמאל אם מוגדר, אחרת ימין (ה־ *אופרנד*) | גבוהה | | `xor` | או בלעדי | `1` מנורמל או מחרוזת ריקה | נמוכה מאוד | | `not` | not | `1` מנורמל או מחרוזת ריקה | נמוכה מאוד | | `and` | and | שמאל אם שקר, אחרת ימין (ה־ *אופרנד*) | נמוכה מאוד | | `or` | or | שמאל אם אמת, אחרת ימין (ה־ *אופרנד*) | נמוכה מאוד | | `?:` | שילוש | אמצע אם תנאי אמת, אחרת ימין (אופרנד) | נמוכה | שני דברים בטבלה זו עושים את רוב העבודה: - **`&&` ו־`||` מחזירים אופרנד, לא בוליאני.** זוהי התכונה שמאפשרת לניבים של Perl לעבוד כפי שהם עובדים. ראו להלן. - **הצורות הסימבוליות וצורות המילה נבדלות בקדימות, לא במשמעות.** `&&` ו־`and` מחשבים את אותה פונקציה לוגית. הם נבדלים בעוצמת הקישור לאופרטורים סביבם. זו הסיבה שאתם רואים `or die` לאחר קריאות לפונקציות אך `||` בתוך ביטויים — הפרק על הניב `or die` מסביר. ## קיצור וכלל החזרת האופרנד `&&` ו־`||` מחושבים משמאל לימין ועוצרים ברגע שהתוצאה נקבעת. - `A && B` — אם `A` הוא שקר, החזר את `A` מבלי לחשב את `B`. אחרת החזר את `B`. - `A || B` — אם `A` הוא אמת, החזר את `A` מבלי לחשב את `B`. אחרת החזר את `B`. חשוב מכך, **ערך ההחזרה הוא האופרנד עצמו**, לא אמת/שקר מנורמל. זה מה שמאפשר לתבניות כמו `$config{port} || 8080` לעבוד: אם `$config{port}` מוגדר (אמיתי), הביטוי הוא ערכו של `$config{port}`; אם לא, הוא `8080`. ```perl my $port = $config{port} || 8080; my $name = $user_input || "anonymous"; my $list = shift || []; ``` אותה תכונה מפעילה את `or die`: ```perl open my $fh, '<', $path or die "open $path: $!"; # ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ # if open returns true, the right-hand operand # the whole expression is never evaluated # is true and we move on ``` `open` מחזיר אמת בהצלחה, undef בכישלון. בהצלחה הקיצור עוצר בשמאל ו־`die` לעולם לא רץ. בכישלון האופרנד הימני מחושב, שהוא הקריאה ל־`die`. ## `//` — defined-or `||` מתייחס ל־`0`, `""`, ו־`"0"` כמו ל־`undef`. לפעמים זה שגוי: `0` שהוגדר הוא ערך אמיתי, לא חסר. `//` מקצר על **מוגדרוּת** במקום על אמיתיוּת: - `A // B` — אם `A` מוגדר, החזר את `A`. אחרת החזר את `B`. ```perl my $port = $config{port} || 8080; # 0 means "use default" — wrong my $port = $config{port} // 8080; # 0 means "0", undef means "use default" my $verbose = $opt{verbose} // 0; # 0 is a real choice ``` צורות ההשמה המורכבות `||=` ו־`//=` חוסכות מכם לחזור על המשתנה בשמאל: ```perl $config{port} //= 8080; # set only if currently undef $cache{$key} ||= compute($key); # set if currently false ``` ## `xor` והיעדרה של צורה בעלת קדימות גבוהה אין `^^` ב־Perl. `xor` קיים רק כצורת מילה בעלת קדימות נמוכה־מאוד, ובניגוד ל־`and`/`or` הוא *אינו* מקצר (הוא לא יכול — שני הצדדים חייבים להיות מחושבים כדי לקבוע את התוצאה). הוא מחזיר `1` מנורמל או `""`, לא אופרנד. ```perl if ($admin xor $guest) { ... } # exactly one of the two ``` עבור `xor` על ערכים ולא על אמיתיוּת, ה־`^` הביטי חל על מספרים שלמים — מכוסה ב־[פרק היישומים](applications.md). ## `!` ו־`not` שניהם שוללים. `!` הוא הצורה הסימבולית בעלת הקדימות הגבוהה; `not` הוא צורת המילה בעלת הקדימות הנמוכה. שניהם מחזירים ערך מנורמל: `1` עבור ״האופרנד היה שקר״, מחרוזת ריקה `""` עבור ״האופרנד היה אמת״. ```perl my $missing = ! $config{port}; # 1 if port is unset/0/""/"0" return if not @items; # cleaner reading than `if !@items` ``` ## השילוש `?:` `COND ? X : Y` הוא בחירה לוגית: אם `COND` הוא אמת הערך הוא `X`, אחרת `Y`. זה לא רק תחביר מתוק עבור `if`/`else` משום שזהו *ביטוי* — יש לו ערך, ניתן להשמה, להחזרה, להעברה כארגומנט. ```perl my $label = $count == 1 ? "1 item" : "$count items"; return $ok ? \%result : undef; ``` היזהרו מקינון: `$a ? $b : $c ? $d : $e` מנותח כ־`$a ? $b : ($c ? $d : $e)` — `?:` משורשרים הם אסוציאטיביים מימין, מה שלרוב הוא מה שאתם רוצים עבור מפל `if/elsif/else` אך כדאי לדעת ולא לנחש. ## מדוע צורות המילה קיימות: קדימות, לא סגנון `||` נקשר חזק יותר מ־`=`. `or` נקשר רפה יותר מ־`=` (או `,`, או כל דבר אחר בעל משקל מוסכם). זוהי כל הסיבה לקיומן של צורות המילה. ```perl my $fh = open $h, '<', $path || die "no $path: $!"; # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ # parses as: open $h, '<', ($path || die "no $path: $!") # which is: open the file named "either $path or the die-message" # which is: catastrophe. my $fh = open $h, '<', $path or die "no $path: $!"; # parses as: ($fh = open $h, '<', $path) or die "no $path: $!" # which does what you meant. ``` כלל אצבע: - בתוך ביטוי, שבו אתם רוצים שהערך יזרום לתוך משתנה או אופרטור אחר: השתמשו ב־`&&`, `||`, `!`, `//`. - לאחר משפט, שבו אתם רוצים שתופעת לוואי (`die`, `warn`, `return`) תפעל בתנאי: השתמשו ב־`or`, `and`, `not`. ## מה כדאי לזכור מהפרק הזה - `&&` ו־`||` אינם פרדיקטים המחזירים 1 או 0 — הם מחזירים אחד מהאופרנדים שלהם. זהו היסוד של `||`, `||=`, `or die`, ושל רוב ניבי ברירת המחדל הקצרים. - `//` הוא `||` עבור מוגדרוּת, לא אמיתיוּת. השתמשו בו כאשר `0` הוא ערך לגיטימי. - צורות המילה קיימות כדי להיקשר רפה יותר מהשמה, לא לצרכי סגנון. - `xor` קיים, אין לו צורה סימבולית, אינו מקצר. ## ראו גם - [perlop — לוגי](../../p5/core/perlop/logical.md) — מלווה מדריך העיון, עם הקשר שורת הקדימות והערות ספציפיות ל־PetaPerl. - [perlop — קדימות](../../p5/core/perlop/precedence.md) — הטבלה המלאה; שורות 5, 15, 16, 22, 23, 24 הן האופרטורים בעמוד זה. - [perlop — שילוש](../../p5/core/perlop/ternary.md) — `?:` כבחירה לוגית.