אופרטורים#

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.

my $port = $config{port} || 8080;
my $name = $user_input  || "anonymous";
my $list = shift        || [];

אותה תכונה מפעילה את or die:

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.

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

צורות ההשמה המורכבות ||= ו־//= חוסכות מכם לחזור על המשתנה בשמאל:

$config{port} //= 8080;   # set only if currently undef
$cache{$key}  ||= compute($key);   # set if currently false

xor והיעדרה של צורה בעלת קדימות גבוהה#

אין ^^ ב־Perl. xor קיים רק כצורת מילה בעלת קדימות נמוכה־מאוד, ובניגוד ל־and/or הוא אינו מקצר (הוא לא יכול — שני הצדדים חייבים להיות מחושבים כדי לקבוע את התוצאה). הוא מחזיר 1 מנורמל או "", לא אופרנד.

if ($admin xor $guest) { ... }   # exactly one of the two

עבור xor על ערכים ולא על אמיתיוּת, ה־^ הביטי חל על מספרים שלמים — מכוסה ב־פרק היישומים.

! ו־not#

שניהם שוללים. ! הוא הצורה הסימבולית בעלת הקדימות הגבוהה; not הוא צורת המילה בעלת הקדימות הנמוכה. שניהם מחזירים ערך מנורמל: 1 עבור ״האופרנד היה שקר״, מחרוזת ריקה "" עבור ״האופרנד היה אמת״.

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 משום שזהו ביטוי — יש לו ערך, ניתן להשמה, להחזרה, להעברה כארגומנט.

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 נקשר רפה יותר מ־= (או ,, או כל דבר אחר בעל משקל מוסכם). זוהי כל הסיבה לקיומן של צורות המילה.

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 — לוגי — מלווה מדריך העיון, עם הקשר שורת הקדימות והערות ספציפיות ל־PetaPerl.

  • perlop — קדימות — הטבלה המלאה; שורות 5, 15, 16, 22, 23, 24 הן האופרטורים בעמוד זה.

  • perlop — שילוש?: כבחירה לוגית.