Присваивание внутри задач тернарных условных операторов Perl

Этот фрагмент кода Perl в моей программе дает неправильный результат.

$condition ? $a = 2 : $a = 3 ;
print $a;

Независимо от того, каково значение $condition, на выходе всегда 3, почему?

Ответов (5)

Решение

Это объясняется в документации Perl .

Из-за приоритета оператора Perl оператор анализируется как

($condition ? $a= 2 : $a ) = 3 ;

Поскольку оператор?: Дает назначаемый результат, результату условия присваивается 3.

Когда условие $ истинно, это означает ($ a = 2) = 3, что дает $ a = 3

Когда $ condition ложно, это означает ($ a) = 3, что дает $ a = 3

Правильный способ написать это

$a = ( $condition ? 2 : 3 );
print $a;

Нас это укусило на работе, поэтому я пишу здесь, надеясь, что другие сочтут это полезным.

Просто чтобы расширить предыдущий ответ ... Если по какой-либо причине назначения должны быть частью условного оператора, вы захотите написать его так:

$condition ? ($a=2) : ($a=3);

Это было бы полезно, если вы назначаете разные переменные в зависимости от условия.

$condition ? ($a=2) : ($b=3);

И если вы выбираете переменную, но назначаете одно и то же, несмотря ни на что, вы даже можете сделать это:

($condition ? $a : $b) = 3;

Одно предложение к ответу Tithonium выше:

Если вы хотите присвоить разные значения одной и той же переменной, это может быть лучше (способ записной книжки):

$ a = ($ условие)? 2: 3;

Если у вас возникло подозрение, что у вас могут быть проблемы с приоритетом, попробуйте выяснить, что, по мнению Perl, вы имели в виду:

perl -MO=Deparse,-p -e '$condition ? $a= 2 : $a= 3 ; print $a;'

В вашем случае это покажет вам:

(($condition ? ($a = 2) : $a) = 3);
print($a);
-e syntax OK

... в этот момент вы должны сказать: «О, это все объясняет»!

Из-за приоритета оператора Perl оператор анализируется как:

($condition ? $a = 2 : $a ) = 3 ;

Поскольку оператор?: Дает назначаемый результат, результату условия присваивается 3.

Когда условие $ истинно, это означает, что $ a = 2 = 3, что дает $ a = 3

Когда $ condition ложно, это означает, что $ a = 3 дает $ a = 3

Правильный способ написать это

$a = $condition ? 2 : 3;

В общем, вам действительно следует избавиться от привычки использовать условные выражения для выполнения присваивания, как в исходном примере - это то, что приводит к тому, что Perl приобретает репутацию предназначенного только для записи.

Хорошее практическое правило состоит в том, что условные выражения предназначены только для простых значений, а не для выражений с побочными эффектами. Когда через восемь месяцев вам или кому-то другому понадобится прочитать этот код, вы бы предпочли, чтобы он читался так?

$x < 3 ? foo($x) : bar($y);

Или вот так?

if ($x < 3) {
  $foo($x);
} else {
  $bar($y);
}