Некоторые сведения о Perl 5/Синтаксис
Синтаксис Perl 5, хотя и наследует некоторые черты таких языков, как Awk и C (и, следовательно, ведет свою родословную от синтаксиса Алгол 68 — как и, по-видимому, большинство распространенных ныне языков программирования), является, пожалуй, одной из наиболее сложных черт языка. В частности — благодаря наличию зачастую множества форм записи одного и того же по своему смыслу кода, а также неочевидности (или, во всяком случае, — непривычности) некоторых своих особенностей.
Примеры неочевидных по смыслу форм
[править]Рассмотрим, для примера, следующий фрагмент кода, выбирающий из списка (Shanghai, Karachi, Mumbai, Delhi, Ahmedabad) строки, содержащие латинскую букву «b»:
grep { /b/ } ("Shanghai", "Karachi", "Mumbai",
"Delhi", "Ahmedabad");
Можно подумать, что следующий фрагмент выведет выбранные таким образом элементы, завершив вывод переводом строки:
print (grep { /b/ } ("Shanghai", "Karachi", "Mumbai",
"Delhi", "Ahmedabad"),
"\n");
Однако, на деле перевод строки не будет выведен, поскольку с точки зрения Perl 5, строка "\n" является… аргументом функции grep, — отнюдь не print.
Исправить ситуацию в данном случае может дополнительная пара скобок вокруг вызова grep:
print ((grep { /a/ } ("Shanghai", "Karachi", "Mumbai",
"Delhi", "Ahmedabad")),
"\n");
Контексты
[править]Выражения и утверждения
[править]Как и некоторые другие языки, Perl 5 предполагает два основных синтаксических контекста:
- выражений (expressions);
- утверждений (statements.)
В простейшем случае, утверждение состоит из одного выражения — присваивания, вызова функции, или иного. Например:
my $a = 3;— объявление скаляра$aв текущей области видимости с начальным значением3;print ($a, "\n");— вызов функцииprintс передачей в качестве аргументов скаляра$a(другими словами, — ссылки на данный скаляр) и строки"\n".
Переход из контекста утверждений в контекст выражений выполняется «автоматически.» Обратный переход возможен благодаря форме do { }, например:
my $a = 42;
my $b = 1 + do {
my $b = f ($a);
## .
g ($b) * h ($b);
};
Как видно из примеров выше, в качестве разделителя утверждений используется точка с запятой ;. Использование разделителя после последнего оператора в { }-блоке не обязательно. (Однако едва ли найдется веская причина опускать оный в многооператорных, многострочных блоках.)
Скалярный и векторный контексты
[править]Вычисление выражений, кроме того, также может происходить в двух различных контекстах:
- ожидания скаляра (скалярный контекст);
- ожидания вектора (массива, списка.)
Так, в примере выше, функция grep выполняется в контексте ожидания вектора (поскольку аргументы функций передаются именно как вектор.) Напротив, в следующем примере, функция будет вызвана в контексте ожидания скаляра:
my $a
= grep { /a/ } ("Shanghai", "Karachi", "Mumbai",
"Delhi", "Ahmedabad");
print ($a, "\n");
## → 4
Как правило, при вызове в скалярном контексте функции, возвращающей вектор, значением является первый элемент возвращаемого вектора. Однако, функция grep определена так, что в скалярном контексте возвращает количество элементов переданного ей списка, удовлетворяющих заданному условию. (Следовательно, в примере выше, значением $a окажется 4.)
Аргумент формы scalar всегда вычисляется в скалярном контексте, позволяя принудительно перейти в данный контекст, подобно:
my @counts = (scalar (@foo), scalar (@bar));
(В то время как без scalar, запись (@foo, @bar) означает объединение списков.)
Функция wantarray возвращает «истину» при вычислении в контексте ожидания вектора и «ложь» в противном случае, что можно использовать при создании функций, имеющих различный смысл в этих контекстах.
Константы
[править]Perl 5 поддерживает числовые константы (как целочисленные, так и с плавающей точкой) «обычного вида» (1, -2, 1.23e4), а также ряд форм для записи строковых и списковых констант, а также строковых «полуконстант-шаблонов» в стиле Bourne shell. В частности:
'hello',q (hello)— строковые константы;"hello, $a",qq (hello, $a)— строки, допускающие подстановку переменных («шаблоны») и особых символов, а также экранирование;qw (hello world)— список из двух элементов (helloиworld);<<разделитель— строковая константа (если разделитель взят в одинарные кавычки или формуq ( )) или «строка-шаблон» (в противном случае), состоящая из строк начиная со следующей и до первой следующей за ней строки программы, совпадающей с разделителем.
В формах " " и qw ( ) доступны следующие \-подстановки:
\разделитель— сам разделитель (один символ); применяется для экранирования неспаренного (или непарного) разделителя;\\— обратная косая черта (\);\a— «звонок»;\n— разрыв (перевод) строки;\t— горизонтальная табуляция;\N{имя}— символ по имени или кодовой позиции Unicode (с ведущимU+.)
Примеры (где  — перевод строки):
"print \"Hello!\\n";"; # → print "Hello!\n";
qq (-\) \\/ \(-\n); # → -) \/ (-
"\N{U+263a}\n"; # → ☺
Отметим, что формы q ( ), qq ( ), qw ( ) (и им подобные) допускают произвольный парный (скобки) или непарный символ в качестве разделителя, подобно: q ~hi~, qw [hello world].
Использование формы q { } особенно удобно в тех случаях, когда строковая константа содержит достаточно широкий набор символов, однако все скобки указанного вида в ней корректно спарены. В частности, когда такая константа является фрагментом кода на каком-либо из «Алгол-подобных» языков программирования. Например:
print (q [print $a[$b[$c]];], "\n");
Переменные
[править]Переменные в Perl обозначаются символами $ (скаляры), @ (векторы или массивы) и % (таблицы или ассоциативные массивы) перед именем. Например (где для формирования списков для инициализации переменных @name и %favorites используются во многом равнозначные списковые операторы , и =>):
my $answer = 42;
my @name = ("Smith", "John");
my %favorites
= ("color" => "green",
"fruit" => "watermelon");
Для объявления переменных используются следующие формы:
my — объявление переменной или переменных с областью видимости — «наиболее вложенным» из текущих блоков;
our — область видимости — текущий модуль;
state — аналогично my, но переменные не будут переинициализированы при повторных выполнениях блока.
Объявить переменные можно в произвольной точке блока. Также, объявление может быть объединено с присваиванием переменным начальных значений (как в примерах выше.) В случае отсутствия такого присваивания, начальным значением объявленных переменных окажется особое «неопределенное» значение (undef.) Для проверки на «определенность» используется функция defined, подобно:
my $a;
print "\$a is undefined\n"
unless (defined ($a));
## → $a is undefined
Кроме того, доступна форма local, позволяющая присвоить значение переменной до завершения текущего блока, полезная в первую очередь для изменения особых переменных Perl,[1] таких как разделитель полей $OFS и разделитель записей $ORS (в контексте действия директивы use English;). Например:
use English qw (-no_match_vars);
local ($OFS, $ORS)
= (" ", "\n");
print ("Answer:", $answer);
## → Answer: 42
Отметим, что объявление переменных является обязательным в контексте действия директив use strict; и use common::sense;, которые автор считает должным рекомендовать для повсеместного использования.
Обращение к элементам списков и таблиц выполняется формами [индекс] и {ключ}, соответственно. При этом:
- индекс первого элемента вектора — 0 (иными словами: смещение, не порядковый номер);
- перед именем переменной указывается символ целевого типа (
$ или @);
- в качестве индексов и ключей могут, в свою очередь, также использоваться списки.
Например (продолжая примеры выше):
print ("Name:", @name[(1, 0)]);
## → Name: John Smith
print ("Favorite color:", $favorites{"color"});
## → Favorite color: green
Циклы
[править]Примерами сложных утверждений являются циклы, частным случаем которых (!) является безусловный цикл-блок,[2] в том числе и используемый после модификаторов if и unless. Например:
foreach my $i ("Shanghai", "Karachi", "Mumbai") {
if ($i =~ /b/) { next; }
print (" ", $i, "\n");
}
{
my $a = "Hello, world!";
print ($a, "\n");
}
Может показаться странным, что блок ({ }) назван частным случаем цикла, однако вне зависимости от наличия образующего цикл модификатора (for, foreach, until, while) в таких блоках доступны обычные операторы управления циклами — last, next и redo. («Истинным» блоком можно считать блок, образуемый формой do { } — которая, однако, сама по себе является выражением, и может требовать завершающую утверждение ;.)
Примечательно, что в то время как операторы управления циклом, примененные в «безусловном» блоке, управляют выполнением самого такого блока, оказавшись под условием они начинают управлять внешним по отношению к этому блоку циклом. Так, выполнение следующего цикла останавливается на элементе "Mumbai", а вовсе не на первом же элементе (как может показаться исходя из наличия безусловного { last; }):
foreach my $i ("Shanghai", "Karachi", "Mumbai") {
{ last; }
if ($i =~ /b/) { last; }
print (" ", $i, "\n");
}
Модификаторы
[править]Роль, которую в других языках нередко играют операторы цикла и условный оператор (контекста утверждений), в Perl 5 отдана модификаторам утверждений, основными из которых являются:
if выражение — выполнить модифицируемый оператор, если значение выражения — истинно;
unless выражение — если значение выражения — ложно;
while выражение — выполнять, пока значение выражения — истинно;
until выражение — выполнять, пока значение выражения — ложно (другими словами: до тех пор, пока не станет истинным);
foreach список — выполнить для каждого элемента списка.
Модификатор указывается или непосредственно после модифицируемого простого утверждения, или непосредственно перед цикл-блоком, например:
print "0xCAFE\n"
if 0x1337;
foreach (1 .. 3) {
print ($_, "\n");
}
Операторы
[править]Perl 5 поддерживает «C-подобный» набор унарных и бинарных операторов (включая и операторы с присваиванием), и единственный тернарный условный оператор ? :.[3] В отличие от C, однако, конкретные классы могут переопределять эти операторы. Далее мы рассмотрим действия операторов «по-умолчанию.»
- Арифметико-логические операторы
-
+, -, *, /, %, **
- сложение, вычитание, умножение, частное и остаток от деления, возведение в степень, соответственно;
- операторы
+ и - также могут пониматься как унарные (сохранение и обращение знака, соответственно);
<, <=, ==, >=, >, !=
- операторы сравнения (меньше, меньше или равно, равно, больше или равно, больше, не равно);
<=>
- знак разности; результатом
$a <=> $b будет -1 если $a меньше $b, 0 в случае равенства, +1 если больше, и «не определено» (undef) если любой из аргументов — «не число» (NaN);
!, not
- логическое отрицание; результат
! $a — истина, если $a — ложно, и наоборот; оператор not отличается более низким приоритетом;
xor
- логическое «исключающее или»; результат
$a xor $b — ложь, если $a и $b оба истинны или оба ложны; истина — в противном случае;
&, |, ^
- поразрядные битовые умножение, сложение и сложение по модулю 2; пример:
123 & 456 → 72 (001111011₂ ⊙ 111001000₂ = 001001000₂);
- эти же операции действительны для строк, понимая их как битовые векторы; так,
"42" & "13" → 02 (0011010000110010₂ ⊙ 0011000100110011₂ = 0011000000110010₂); отметим, однако, что в понимании конкретного значения как числа или строки, Perl может следовать весьма неочевидной логике;
~
- поразрядное битовое дополнение (отрицание); так,
(~ 42) & 077 → 21 (11⋯11010101₂ ⊙ 111111₂ = 10101₂);
- подобно
&, | и ^ выше, эта операция действительна и для строк;
<<, >>
- целочисленный битовый сдвиг (умножение и деление на 2ⁿ.)
- Условные операторы
-
? :
- тернарный условный оператор контекста выражения; в форме
c () ? t () : f () первым вычисляется выражение c (); если результат — истинное значение, — вычисляется t (); в противном случае — вычисляется f (); последнее вычисленное выражение — результат оператора в целом;
&&, ||, //
- условные операторы «и», «или», «первое определенное»:
- в форме
a () && b () первым вычисляется выражение a () и, если оно истинно, — вычисляется b ();
- в форме
a () || b () — b () вычисляется в случае, если a () — ложно;
- в форме
a () // b () — b () вычисляется в случае, если a () — «не определено» (undef);
- последнее вычисленное выражение — результат оператора в целом;
and, or
- аналогичны
&&, ||, однако имеют приоритет меньший, чем присваивание; полезны в форме my $r = frob ($arg) or die ();.
- Строковые операторы
-
.
- объединение строк;
x
- повтор строки; так, результат
"a" x 5 — "aaaaa";
lt, le, eq, ge, gt, ne, cmp
- сравнение строк; подобно
<, <=, ==, >=, >, !=, и <=>, соответственно.
- Списковые операторы
-
,
- объединение списков (включая списки, состоящие из одного элемента); так,
(qw (a b), ("c", "d"), "e") — список, состоящий из элементов a, b, c, d, e;
=>
- аналогично
,, однако понимает аргумент слева как строку, если оный является идентификатором (состоит только из букв, цифр и знака _, и не начинается с цифры); так, (a => "b") — список a, b; в отличие от (a, "b"), где a — вызов функции a;
x
- повтор списка; так, результат
("a", "b") x 2 — список a, b, a, b.
- Изменяющие операторы
-
=
- простое присваивание.
++, --
- инкремент и декремент; значением
$a++ является значение $a до изменения, ++$a — после; аналогично и для --;
+=, -=, *=, /=, %=, **=
- арифметические операции (см. выше) с присваиванием результата; так,
$a[f ($b)] += $c равносильно $a[f ($b)] = $a[f ($b)] + $c за тем лишь исключением, что f ($b) в первом случае будет вычислено единожды;
&=, |=, ^=
- поразрядные битовые операции с присваиванием результата;
<<=, >>=
- целочисленный битовый сдвиг с присваиванием результата;
&&=, ||=, //=
- условные операторы с присваиванием результата;
$a &&= $b выполнит присваивание $a = $b, если $a — истинно; $a ||= $b — если $a — ложно; $a //= $b — если $a — «не определено» (undef);
.=
- объединение строк с присваиванием результата;
x=
- повтор строки с присваиванием результата.
- Операторы ссылок (references)
-
\
- ссылка на л-значение (другими словами, на выражение, которое может стоять слева от оператора присваивания
=); так, \@a — ссылка на «ячейку памяти», хранящую вектор @a;
->
- обращение по ссылке; применяется для:
- обращения к элементу вектора или таблицы по ссылке; так, если
$href — ссылка на таблицу, то $href->{"color"} — элемент этой таблицы с ключом color;
- вызова функции по ссылке; подобно:
$fn_ref->(@args);
- вызова метода класса или объекта, подобно:
Local::Class->new (@args) (метод new класса Local::Class) и $obj->frob (@args) (метод frob объекта, ссылка на который хранится в $obj);
$, @, %, &
- не операторы; будучи поставлены перед выражением, данные символы позволяют обратиться к скаляру, вектору, таблице и функции, на который ссылается данное выражение; «сложные» выражения следует заключать в фигурные скобки, подобно:
${frob_ref (@args) // $default_ref} — обращение к скаляру, на который ссылается скаляр, возвращаемый функцией frob_ref, или на который ссылается $default_ref, если возвращенное frob_ref значение — не определено.
- Скалярный оператор
,
-
- в скалярном контексте, форма
a (), b () вычисляет выражения a (), b (), и возвращает результат последнего; применяется в случаях, когда первое из выражений вычисляется только ради побочного действия, подобно: ($a++, $b++).
Ссылки
[править]