[ Content | View menu ]

Приоритеты операторов в Perl

Опубликовано 15.05.2009

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

Сначала был примерно такой код:

while(<STDIN>)
{
    if(($name) = $_ =~ /^\s*source (.*)\.sql/i)
    {
        if (&function $name)
        {
            # do something with $name
        }
    }
}

Логично было бы объединить два условия в одно:

while(<STDIN>)
{
    if(($name) = $_ =~ /^\s*source (.*)\.sql/i && &function $name)
    {
        # do something with $name
    }
}

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

Для простоты рассмотрим однострочник на Perl, локализующий эту проблему:

echo o|perl -ne 'print "aga\n" if (($o) = $_ =~ /(a)/ && 1)'

Здесь в одном условии встречаются три оператора: присваивания =, привязки =~, а также логическое И &&. Согласно perldoc perlop, оператор присваивания имеет более низкий приоритет, чем два остальных, поэтому выполняется последним, и код можно представить в виде:

echo o|perl -ne 'print "aga\n" if (($o) = ( $_ =~ /(a)/ && 1 ) )'

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

Поэтому при объединении условий всегда нужно проверять приоритеты операторов и группировать условия вручную:

while(<STDIN>)
{
    if( ( ($name)=$_=~/^\s*source (.*)\.sql/i ) && &function $name)
    {
        # do something with $name
    }
}
«
»

3 комментария

Write a comment - TrackBack - RSS Comments

  1. Comment by sergey:

    я тоже нарывался на такие грабли и теперь всегда каждое условие беру с скобки.

    17.05.2009 @ 07:54
  2. Comment by Alexey:

    На самом деле более в первловом стиле было бы написать:

    while() {
    next unless /bla-bla-bla/;
    my $name = $1;
    next unless &$function();
    bla-bla-bla
    }

    Меньше уровень вложенности – проще читать код. И $_ долой из кода, наличие этой переменной не делает код более очевидным, имхо. А вместо позволяет запускать скрипт двумя способами: cat file | ./script и ./script file

    18.05.2009 @ 22:45
  3. Comment by Alexey:

    Оп-па, пропали <> из кода (угловые скобочки без ничего в условии while).
    В последней фразе идея такая, что STDIN указывать не нужно.

    18.05.2009 @ 22:47
Write comment

Я не робот.