Присвоение внутри Perl троичных задач условного оператора - PullRequest
40 голосов
/ 12 августа 2008

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

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

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

Ответы [ 5 ]

79 голосов
/ 12 августа 2008

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

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

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

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

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

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

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

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

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

40 голосов
/ 06 сентября 2008

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

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

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

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

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

21 голосов
/ 22 августа 2008

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

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

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

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

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

($condition ? $a : $b) = 3;
4 голосов
/ 16 сентября 2008

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

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

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

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

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

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

$a = $condition ? 2 : 3;

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

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

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

Или вот так?

if ($x < 3) {
  $foo($x);
} else {
  $bar($y);
}
0 голосов
/ 04 сентября 2008

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

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

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

...