Содержание
Операторы обеспечивают простой синтаксис для часто используемых действий. Они обладают специальным синтаксисом и позволяют манипулировать значениями.
Вернемся к нашей турнирной таблице из предыдущей главы. Допустим вам потребовалось графически отобразить количество выигранных каждым игроком сетов в турнире. Следующий пример выводит на экран строки из символов X для создания горизонтальной столбчатой диаграммы:
use v6;
my @scores = 'Ana' => 8, 'Dave' => 6, 'Charlie' => 4, 'Beth' => 4;
my $screen-width = 30;
my $label-area-width = 1 + [max] @scoresE<raquo>.keyE<raquo>.chars;
my $max-score = [max] @scoresE<raquo>.value;
my $unit = ($screen-width - $label-area-width) / $max-score;
for @scores {
my $format = '%- ' ~ $label-area-width ~ "s%s\n";
printf $format, .key, 'X' x ($unit * .value);
}
На экран будет выведен следующий результат:
Ana XXXXXXXXXXXXXXXXXXXXXX
Dave XXXXXXXXXXXXXXXX
Charlie XXXXXXXXXXX
Beth XXXXXXXXXXX
Строка в примере:
my @scores = 'Ana' => 8, 'Dave' => 6, 'Charlie' => 4, 'Beth' => 4;
... содержит три разных оператора: =, =>, и ,.
Оператор = является оператором присваивания . Он берет значения, расположенные справа, и сохраняет их в переменной слева, а именно в переменной @scores.
Как и в других языках, основанных на синтаксисе C, Perl 6 допускает сокращенные формы для записи обычных присвоений. То есть вместо $var = $var op EXPR
использовать $var op= EXPR. Например, ~ (тильда) - оператор строковой конкатенации (объединения); для добавления текста к концу строки достаточно выражения $string ~= "text", которое является эквивалентом $string = $string ~ "text".
Оператор => ( => - толстая стрелка ) создает Пару ( pair ) объектов. Пара содержит один ключ и одно значение; ключ располагается слева от оператора =>, а значение - справа. Этот оператор имеет одну особенность: парсер интерпретирует любой идентификатор в левой части выражения как строку. С учетом этой особенности строку из примера можно записать следующим образом:
my @scores = Ana => 8, Dave => 6, Charlie => 4, Beth => 4;
И наконец, оператор , создает Парселы ( Parcel ) - последовательности объектов. В данном случае объектами являются пары.
Все три рассмотренные оператора являются инфиксными, то есть располагаются между двумя термами (terms). Термом может быть литерал, например 8 или "Dave", или комбинация других термов и операторов.
В предыдущей главе были использованы также другие типы операторов. Они сдержали инструкцию %games{$p1}++;. Постциркумфиксный (postcircumfix) оператор {...} указан после ( post) терма, и содержит два символа ( открывающую и закрывающую фигурные скобки), которые окружают (circumfix) другой терм. После postcircumfix оператора следует обычный постфиксный оператор ++, который инкрементирует (увеличивает на единицу) переменную слева. Не допускается использование пробела между термом и его постфиксными (postfix) или постциркумфиксным (postcircumfix ) операторами.
Еще один тип операторов - префиксный (prefix). Они указываются перед термом. Примером такого оператора служит -, который инвертирует указанное числовое значение: my $x = -4.
Оператор - еще означает вычитание, поэтому say 5 - 4 напечатает 1. Чтобы отличить префиксный оператор - от инфиксного -, парсер Perl 6 отслеживает контекст: ожидается ли в данный момент инфиксный оператор или терм. У терма может отсутствовать или указано сколько угодно префиксных операторов, то есть возможна следующее выражение : say 4 + -5. В нем, после + ( инфиксного оператора ), компилятор ожидает терм, и поэтому следующий за ним - интерпретируется как префиксный оператор для терма 5.
Следующая строка содержит новые особенности :
my $label-area-width = 1 + [max] @scoresE<raquo>.keyE<raquo>.chars;
Начинатся указанная строка с безобидного определения переменной my $label-area-width и оператора присвоения. Затем следует простое операция сложения 1 + .... Правая часть оператора + более сложная.
Инфиксный оператор max возвращает большее из двух значений, то есть 2 max 3 вернет 3. Квадратные скобки вокруг оператора дают инструкцию Perl 6 применить указанный в них оператор к списку поэлементно. Поэтому конструкция [max] 1, 5, 3, 7 эквивалентна 1 max 5 max 3 max 7, а результатом будет число 7.
Также можно использовать [+] для получения суммы элементов списка, [*] - произведения и [<=] для проверки отсортирован ли список по убыванию.
Следующим идет выражение @scores».key».chars. Так же, как @variable.method вызывает метод у @variable, @array».method производит вызовы метода для каждого элемента в массиве @array и возвращает список результатов.
» представляет собой гипер опрератор. Это также Unicode символ. В случае невозможности ввода данного символа, его можно заменить на два знака больше (>>) . За неимением Ubuntu под рукой следующее решение привожу в оригинале: Ubuntu 10.4: In
System/Preferences/Keyboard/Layouts/Options/Compose Key position select one of
the keys to be the "Compose" key. Then press Compose-key and the "greater than"
key twice.
Результатом @scores».key является список ключей пар в @scores, а @scores».key».chars возвращает список длин ключей в @scores.
Выражение [max]@scores».key».chars выдаст наибольшее из значений. Это так же идентично следующему коду:
@scores[0].key.chars
max @scores[1].key.chars
max @scores[2].key.chars
max ...
Предваряющие выражение (circumfix) квадратные скобки являются редукционным мета опрератором, который преобразует содержащийся в нем инфиксный оператор в оператор, который ожидает список (listop), а также последовательно осуществляет операции между элементами каждого из списков.
Для отображения имен игроков и столбцов диаграммы, программе необходима информация о количестве позиций на экране, отводимом для имен игроков. Для этого вычисляется максимальная длина имени и прибавляется 1 для отделения имени от начала столбца диаграммы. Полученный результат будет длиной подписи к столбцу диаграммы (с одним уточнением: столбцы - горизотальные ).
Следующий текст определяет наибольшее количество очков:
my $max-score = [max] @scoresE<raquo>.value;
Область диаграммы имеет ширину $screen-width - $label-area-width, равную разнице ширины экрана и длины подписи для данного столбца. Таким образом для каждой строки рейтинга потребуется вывести на экран :
my $unit = ($screen-width - $label-area-width) / $max-score;
... количество символов X. В процессе вычислений используются инфиксные операторы - и /.
Теперь вся необходимая информация известна и можно построить диаграмму:
for @scores {
my $format = '%- ' ~ $label-area-width ~ "s%s\n";
printf $format, .key, 'X' x ($unit * .value);
}
Данный код циклически обходит весь список @scores, связывая каждый из элементов со специальной переменной $_. Для каждого элемента используется встроенная функция printf , которая печатает на экране имя игрока и строку диаграммы. Данная функция похожа на printf в языках C и Perl 5. Она получает строку форматирования, которая описывает каким образом печатать следующие за ней параметры. Если $label-area-width равна 8, то строка форматирования будет "%-8s%s\n". Это значит, что строка %s занимает 8 позиций ('8') и выравнена по левому краю, за ней следует еще строка и символ новой строки '\n'.
В нашем случае первой строкой является имя игрока. второй - строка диаграммы.
Инфиксный оператор x, или оператор повторения, формирует строку столбца. Он возвращает строку, состоящую из левого операнда, повторенного число раз, заданное правым операндом. То есть 'ab' x 3 вернет строку 'ababab'. .value возвращает значение текущей пары, ($unit * .value) умножает его на $unit, и 'X' x ($unit * .value) возвращает строку с требуемым количеством символов.