Некоторые сведения о 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++)
.
Ссылки
[править]