Операторы

Некоторые называют Perl «оператор-ориентированным языком». Чтобы понять программу на Perl, вы должны понять как её операторы взаимодействуют со своими операндами.

Оператор в Perl — это набор из одного или более символов, используемый как часть синтаксиса языка. Каждый оператор оперирует нолём или более операндов. Воспринимайте операторы как особый вид функций, понимаемых парсером, а их операторы — как аргументы.

Свойства операторов

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

perldoc perlop и perldoc perlsyn предоставляют обширную информацию об операторах Perl, но документация подразумевает, что вы уже знакомы с некоторыми деталями того, как они работают. Основные понятия компьютерных наук могут выглядеть внушительно, но когда вы проберётесь через их названия, они довольно очевидны. Неявно вы их уже понимаете.

Приоритет

Приоритет оператора определяет, когда Perl должен вычислить его в выражении. Порядок вычисления следует от наивысших приоритетов к наинизшим. Так как приоритет умножения выше, чем приоритет сложения, результатом вычисления 7 + 7 * 10 будет 77, а не 140.

Чтобы заставить какие-либо операторы вычисляться раньше других, сгруппируйте их подвыражения в круглые скобки. В выражении (7 + 7) * 10 группировка сложения в одно целое приводит к тому, что оно вычисляется раньше умножения. Результатом будет 140.

perldoc perlop содержит таблицу приоритетов. Прочитайте её, поймите, но не утруждайте себя запоминанием (почти никто этого не делает). Лучше сохраняйте свои выражения простыми и добавляйте скобки для прояснения своего замысла.

В случае, если два оператора имеют одинаковый приоритет, ситуацию разрешают другие факторы, такие как ассоциативность (Ассоциативность) и фиксность (Фиксность).

Ассоциативность

Ассоциативность оператора определяет, вычисляется он слева направо или справа налево. Сложение левоассоциативно, поэтому 2 + 3 + 4 сначала вычисляет 2 + 3, а затем добавляет к результату 4. Возведение в степень правоассоциативно, поэтому 2 ** 3 ** 4 вычисляет сначала 3 ** 4, а затем возводит 2 в 81-ую степень.

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

Базовый модуль B:Deparse — бесценный отладочный инструмент. Выполните perl -MO=Deparse,-p с фрагментом кода чтобы уведить в точности как Perl обрабатывает приоритет и ассоциативность операторов. Флаг -p добавляет дополнительные групирующие скобки, которые часто проясняют порядок вычисления.

Имейте ввиду, что оптимизатор Perl упростит математические операции как описано в предыдущих примерах; вместо этого используйте переменные, как в $x ** $y ** $z.

Арность

Арность оператора — это количество операндов, которыми он оперирует. Нольарный оператор имеет ноль операндов. Унарный оператор имеет один оператор. Бинарный оператор имеет два операнда. Тернарный оператор имеет три операнда. Оператор списочной арности оперирует списком операндов. Документация и примеры использования оператора должны сделать его арность ясной.

Например, арифметические операторы — бинарные, и обычно левоассоциативные. 2 + 3 - 4 сначала вычисляет 2 + 3; сложение и вычитание имеют одинаковый приоритет, но они левоассоциативные и бинарные, поэтому правильный порядок вычисления применяет самый левый оператор (+) к двум самым левым операндам (2 и 3), а затем применяет правый оператор (-) к результату первой операции и правому операнду (4).

Новичков в Perl часто сбивает с толку взаимодействие между операторами списочной арности — особенно вызовами функций — и вложенными выражениями. Хотя скобки обычно помогают, опасайтесь запутанности парсинга выражения:

    # вероятно ошибочный код
    say ( 1 + 2 + 3 ) * 4;

…которое выводит значение 6 и (вероятно) в целом возвращает 4 (возвращаемое значение say, умноженное на 4). Парсер Perl успешно интерпретирует скобки как постциркумфиксные (Фиксность) операторы, обозначающие аргументы say, а не циркумфиксные скобки, группирующие выражение для изменения приоритета.

Фиксность

Фиксность оператора — это его расположение по отношению к своим операндам:

Типы операторов

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

Числовые операторы

Числовые операторы налагают числовой контекст на свои операнды. Эти операторы — стандартные арифметические операторы, такие как сложение (+), вычитание (-), умножение (*), деление (/), возведение в степень (**), остаток от деления (%), их вариации (+=, -=, *=, /=, **= и %=), а также постфиксный и префиксный автодекремент (--).

Оператор автоинкремента имеет специальное строковое поведение (Специальные операторы).

Некоторые операторы сравнения налагают числовой контекст на свои операнды. Это числовое равенство (==), числовое неравенство (!=), больше чем (>), меньше чем (<), больше или равно (>=), меньше или равно (<=) и оператор сравнения (<=>).

Строковые операторы

Строковые операторы налагают строковый контекст на свои операнды. Это положительная и отрицательная привязка регулярных выражений (=~ and !~ соответственно) и конкатенация (.).

Некоторые операторы сравнения налагают строковый контекст на свои операнды. Это строковое равенство (eq), строковое неравенство (ne), больше чем (gt), меньше чем (lt), больше или равно (ge), меньше или равно (le) и оператор строкового сравнения (cmp).

Логические операторы

Логические операторы налагают булев контекст на свои операнды. Это операторы &&, and, || и or. Все они инфиксные и проявляют поведение короткого замыкания (Короткое замыкание). Словесные варианты имеют более низкий приоритет, чем их пунктуационные формы.

Оператор определено-или, //, проверяет определённость своего операнда. В отличие от ||, который проверяет истинность своего операнда, // возвращает истинное значение даже если его операнд вычисляется в числовой ноль или пустую строку. Это особенно полезно для установки параметров по умолчанию:

    sub name_pet
    {
        my $name = shift // 'Fluffy';
        ...
    }

Тернарный условный оператор (?:) принимает три операнда. Он вычисляет первый операнд в булевом контексте и возвращает второй операнд, если первый — истина, или третий — в противном случае:

    my $truthiness = $value ? 'true' : 'false';

Префиксные операторы ! и not возвращают логическую противоположность булева значения своих операндов. not — низкоприоритетная версия !.

Оператор xor — инфиксный оператор, вычисляющий исключающее или своих операндов.

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

Побитовые операторы обрабатывают свои операнды численно на битовом уровне. Эти операторы не очень распространены. Они включают левый сдвиг (<<), правый сдвиг (>>), побитовое и (&), побитовое или (|) и побитовое исключающее или (^), а также их варианты (<<=, >>=, &=, |= и ^=).

Специальные операторы

Оператор автоинкремента имеет специальное поведение. При использовании на значении с числовым компонентом (Кешированное преобразование типов), оператор инкрементирует этот числовой компонент. Если значение очевидно строка (и не имеет числового компонента), оператор инкрементирует это строковое значение так, что a становится b, zz становится aaa и a9 становится b0.

    my $num = 1;
    my $str = 'a';

    $num++;
    $str++;
    is( $num,   2, 'numeric autoincrement' );
    is( $str, 'b', 'string autoincrement'  );

    no warnings 'numeric';
    $num += $str;
    $str++;

    is( $num, 2, 'numeric addition with $str'    );
    is( $str, 1, '... gives $str a numeric part' );

Оператор повторения (x) — инфиксный оператор со сложным поведением. В списочном контексте, когда передан список, он возвращает этот список, повторённый количество раз, определяемое вторым операндом. В списочном контексте если передан скаляр, он выдаёт строку, состояющую из строкового значения его первого операнда, конкатенированного с собой количество раз, определяемое вторым операндом.

В скалярном контексте оператор всегда выдаёт конкатенированную строку, соответствующим образом повторённую. Например:

    my @scheherazade = ('nights') x 1001;
    my $calendar     =  'nights'  x 1001;
    my $cal_length   =  length $calendar;

    is( @scheherazade, 1001, 'list repeated' );
    is( $cal_length,   1001 * length 'nights',
                       'word repeated' );

    my @schenolist   =  'nights'  x 1001;
    my $calscalar    = ('nights') x 1001;

    is( @schenolist, 1, 'no lvalue list' );
    is( length $calscalar,
        1001 * length 'nights', 'word still repeated' );

Инфиксный оператор диапазона (..) генерирует список элементов в списочном контексте:

    my @cards = ( 2 .. 10, 'J', 'Q', 'K', 'A' );

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

В булевом контексте оператор диапазона становится оператором триггера. Этот оператор выдаёт ложное значение до тех пор, пока его левый операнд — истина. Это значение остаётся истинным, пока правый оператор — истина, после чего вновь становится ложным, пока левый операнд снова не станет истинным. Представьте разбор текста формального письма следующим образом:

    while (/Hello, $user/ .. /Sincerely,/)
    {
        say "> $_";
    }

Оператор запятая (,) — инфиксный оператор. В скалярном контексте он вычисляет свой левый операнд, а затем возвращает значение, полученное при вычислении правого операнда. В списочном контексте он вычисляет оба операнда в порядке слева направо.

Оператор толстой запятой (=>) кроме того автоматически заключает в кавычки любое голое слово, использованное как его левый операнд (Хеши).