2009-11-12 3 views
3

Я работаю над Perl, и я столкнулся с нечетным результатом с помощью условного оператора.Операция условного оператора Odd Perl

Код в вопросе:

($foo eq "blah") ? @x = @somearray : @y = ("another","array"); 

Попытка скомпилировать этот код приводит к ошибке "Assignment to both a list and a scalar at XXX line YY, near ');'". Пытаясь определить источник ошибки, я написал это, используя пару различных способов представления массива в Perl, и все они возвращаются с той же ошибкой. Теперь я сначала подумал, что это какая-то немая очевидная ошибка с операторами присваивания, но только, чтобы удовлетворить мое любопытство, я переписал заявление в более подробном виде:

if($foo eq "blah") { 
    @x = @somearray; 
} else { 
    @y = ("another","array"); 
} 

Этой версия коды компилируется прекрасно.

Есть ли какое-то тонкое различие между тем, как работает условный оператор и выполняется базовое оператор if-else, которое я здесь отсутствует? Я всегда понимал условный оператор как краткую версию второго оператора. Если между ними нет функциональной разницы, почему объект Perl должен быть первым, но не вторым?

+4

Лично я бы описал второй код образец как «более четкий» и «более простой», а не «подробный». – qid

+0

s/тройной/условный/!!! Могло быть более одного троичного оператора. – Ether

+0

Извинения, я, конечно, не имею проблемы со второй версией, и я бы не судил человека за его использование! Возможно, «более явный» был бы лучшим способом выразить это, хотя я не имел в виду многословный, чтобы оторваться от негативной коннотации. – warhorus

ответ

15
 
$ perl -MO=Deparse -e'($foo eq "blah") ? @x = @somearray : @y = ("another","array");' 
Assignment to both a list and a scalar at -e line 1, near ");" 
-e had compilation errors. 
$foo eq 'blah' ? (@x = @somearray) : @y = ('another', 'array'); 
$ perl -MO=Deparse -e'($foo eq "blah") ? @x = @somearray : (@y = ("another","array"));' 
$foo eq 'blah' ? (@x = @somearray) : (@y = ('another', 'array')); 
-e syntax OK 

Примечание круглые скобки: ?: связывает сильнее, чем =.

+0

Спасибо, работал как шарм! – warhorus

+6

Хотя именно поэтому Perl не нравится код, я бы сказал, что реальный корень ошибки - это злоупотребление оператором '?:'. –

7

В документации perlop четко указано, что вы должны поместить круглые скобки вокруг операторов присваивания.

Несоблюдение круглых скобок является стержнем для вашей спины, если вы не понимаете приоритет оператора. Прекратите пытаться быть слишком умным для своего же блага!

+1

«пытается быть слишком умным для вашего же блага» - это хорошее определение программиста :) – Ether

+3

У меня были горячие споры с «программистами», которые мучают идею использования круглых скобок. Это нормально, если вы сохраняете таблицу приоритетов оператора в своей голове и не меняете языки на регулярной основе. Я программировал уже более 19 лет, и я часто меняю языки, чтобы не делать предположений о базовом языке. Плюс это означает, что я могу переносить выражения с меньшими рисками. –

+0

Я сознательно воздержался от запоминания таблиц приоритетов C и C++. Я полагаю, что буду делать меньше вреда, если я не знаю, где идут парсеры. –

9

Условный оператор Perl, предназначается, чтобы быть

переменная $ = (выражение)? истинное назначение: ложное присвоение;

Что вы делаете, похоже, что он должен работать и в основном такой же, как и оператор if/else. Но он просто отличается от нормы, чтобы иметь проблемы.

+0

В C и Perl вполне допустимо игнорировать результат выражения. –

+1

@PP Да, но не к бедному соку, читающему его. – Schwern

2

Это было бы хорошим местом для использования операторов более низкого приоритета «и» и «или».

$foo eq 'blah' and @x = @somearray or @y = ('another', 'array'); 

при условии, что вы уверены, что @x = @somearray всегда будет правдой. или вы можете перевернуть их.

+0

Во имя чрезмерного обмана, '$ foo eq 'blah' и (undef, @x) = (undef, @somearray) или @y = ('another', 'array');' будет работать, даже если '@ somearray == 0': D – ephemient

+1

Я не согласен, это было бы полезно использовать для 'if() {} else {}'. Все остальное трудно читать и чрезмерно умно. Очевидная путаница в других комментариях обеспечивает независимую проверку трудности, присущей чрезмерному использованию и злоупотреблению оператором короткого замыкания и оператором. – daotoad

+0

[предыдущий комментарий удален за то, что он просто ошибается] – mob

6

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

$x = ($foo eq "blah") ? $somevalue : ("another","array"); 

Если условное значение было ложным, $x вместо этого было бы присвоено единственное целочисленное значение 2 (количество элементов в третьем аргументе).

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

# this is wrong, for the same order-of-operations reasons as with arrays 
($foo eq "blah") ? $x = $somevalue : $x = "another value"; 

Это было бы разумным (и лучший) способ разрешения ситуации:

$x = ($foo eq "blah") ? $somevalue : "another value"; 

Аналогично , вы можете оптимизировать исходный код таким образом:

@x = ($foo eq "blah") ? @somearray : ("another","array"); 
+0

Ортогональный или нет, это отличный момент, чтобы иметь в виду, имея дело с оператором?:! – warhorus

+0

... за исключением того, что исходный код является абсурдно сложным и присваивает '@ x' в одном случае и' @ y' в другом случае. – ephemient

+0

'($ foo eq" blah ")? @x: @y = ($ foo eq "blah")? @somearray: qa (другой массив); 'будет вести себя как исходный код. – ephemient

Смежные вопросы