Здесь происходит множество тонких вещей. Во-первых, ..
- это два совершенно разных оператора в зависимости от контекста, в котором он вызывается. В контексте списка он создает список значений (с шагом в 1) между заданной начальной и конечной точками.
@numbers = 1 .. 3; # 1, 2, 3
@letters = 'a' .. 'c'; # a, b, c (Yes, Perl can increment strings)
Поскольку print
интерпретирует свои аргументы в контексте списка
print 'a' .. 'c'; # <-- this
print 'a', 'b', 'c'; # <-- is equivalent to this
В скалярном контексте ..
является оператором триггера. С Операторы диапазона в perlop:
Это ложно, если его левый операнд ложен. Однажды левый
операнд равен true, оператор диапазона остается истинным до тех пор, пока правильный операнд
истина, ПОСЛЕ того, как оператор диапазона снова становится ложным.
Присваивание скалярному значению, как в $a = ...
, создает скалярный контекст. Это означает, что ..
в print ($a = 'a' .. 'c')
является экземпляром оператора триггера, а не оператором создания списка.
Оператор триггера предназначен для использования при фильтрации строк в файле. например,
while (<$fh>) {
print if /first/ .. /last/;
}
будет печатать все строки в файле, начиная с той, которая содержит first
и заканчивая той, которая содержит last
.
У оператора триггера есть дополнительная магия, разработанная для упрощения фильтрации по номеру строки.
while (<$fh>) {
print if 10 .. 20;
}
напечатает строки с 10 по 20 файла. Это достигается с помощью особого поведения:
Если любой операнд скаляра ..
является постоянным выражением, то
операнд считается истинным, если он равен (==
) текущему входу
номер строки (переменная $.
).
Строки a
и c
являются константными выражениями, поэтому они вызывают этот особый случай. Они не числа, но они используются как числа (==
- числовое сравнение). Perl будет преобразовывать скалярные значения между строками и числами по мере необходимости. В этом случае оба значения нумеруются до 0. Поэтому
print ($a = 'a' .. 'c'); # <-- this
print ($a = 0 .. 0); # <-- is effectively this
print ($a = ($. == 0) .. ($. == 0)); # <-- which is really this
Мы приближаемся ко дну тайны. К следующему биту. Больше от perlop:
Возвращаемым значением является либо пустая строка для false, либо последовательность
число (начиная с 1) для истины. Порядковый номер сбрасывается для
каждый встреченный диапазон. Конечный порядковый номер в диапазоне имеет
строка "E0" добавлена к нему
Если вы еще не прочитали ни одной строки из файла, $.
будет undef
, что равно 0
в числовом контексте. 0 == 0
имеет значение true, поэтому ..
возвращает истинное значение. Это первое истинное значение, поэтому оно 1
. Поскольку и левая и правая стороны имеют значение true, первое истинное значение также является последним истинным значением, а к возвращаемому значению добавляется суффикс E0
«это последнее значение». Это , поэтому print ($a = 'a' .. 'c')
печатает 1E0
. Если вы установите $.
в ненулевое значение, ..
будет ложным и вернет пустую строку.
print ($a = 'a' .. 'c'); # prints "1E0"
$. = 1;
print ($a = 'a' .. 'c'); # prints nothing
Самая последняя часть головоломки (и я мог бы зайти слишком далеко) состоит в том, что оператор присваивания возвращает значение. В этом случае это значение присваивается $a
1 - 1E0
. Это значение является то, что в конечном итоге выплевывает print
.
1: Технически, назначение создает lvalue для назначенного элемента. т.е. он возвращает lvalue для переменной $a
, которая затем оценивается в 1E0
.