Приоритеты операторов в Perl
Опубликовано 15.05.2009
Отлаживая один скрипт, в очередной раз напоролся на банальные грабли, иллюстрирующие красоту и мощь языка Perl.
Сначала был примерно такой код:
{
if(($name) = $_ =~ /^\s*source (.*)\.sql/i)
{
if (&function $name)
{
# do something with $name
}
}
}
Логично было бы объединить два условия в одно:
{
if(($name) = $_ =~ /^\s*source (.*)\.sql/i && &function $name)
{
# do something with $name
}
}
Но после этого условие стало выполняться для каждой строки STDIN, вне зависимости от того, совпадает она с шаблоном или нет. Попробуем разобраться.
Для простоты рассмотрим однострочник на Perl, локализующий эту проблему:
Здесь в одном условии встречаются три оператора: присваивания =
, привязки =~
, а также логическое И &&
. Согласно perldoc perlop
, оператор присваивания имеет более низкий приоритет, чем два остальных, поэтому выполняется последним, и код можно представить в виде:
Логическая операция в больших скобках в списковом контексте возвращает массив, содержащий пустое значение, операция присваивания выполняется успешно и условие выполняется.
Поэтому при объединении условий всегда нужно проверять приоритеты операторов и группировать условия вручную:
{
if( ( ($name)=$_=~/^\s*source (.*)\.sql/i ) && &function $name)
{
# do something with $name
}
}
я тоже нарывался на такие грабли и теперь всегда каждое условие беру с скобки.
На самом деле более в первловом стиле было бы написать:
while() {
next unless /bla-bla-bla/;
my $name = $1;
next unless &$function();
bla-bla-bla
}
Меньше уровень вложенности – проще читать код. И $_ долой из кода, наличие этой переменной не делает код более очевидным, имхо. А вместо позволяет запускать скрипт двумя способами: cat file | ./script и ./script file
Оп-па, пропали <> из кода (угловые скобочки без ничего в условии while).
В последней фразе идея такая, что STDIN указывать не нужно.