07 апреля 2020

Разные операции

    В этом параграфе собраны операции, которые не вошли ни в одну из рассмотренных нами групп операций. Две из них упоминались при описании массивов и хешей (операции диапазон и запятая), а третья является единственной тернарной операцией языка Perl (операция выбора).
Операция диапазон
     Бинарная операция диапазон ".." по существу представляет две различных операции в зависимости от контекста, в котором она используется.
     В списковом контексте, если ее операндами являются числа (числовые литералы, переменные или выражения, возвращающие числовые значения), она возвращает список, состоящий из последовательности увеличивающихся на единицу целых чисел, начинающихся со значения, определяемого левым операндом, и не превосходящих числовое значение, представленное правым операндом. Операцию диапазон часто используют для задания значений элементов массивов и хешей, а также их фрагментов (см. главу 3). Она удобна для организации циклов for и f oreach:

# Напечатает числа от 1 до 5, каждое на новой строке, foreach $cycle (1..5){ print "$cycle\n"; }
# Напечатает строку "12345".
for(l..5){
print; '
}
Замечание
Если значение какого-либо операнда не является целым, оно приводится к целому отбрасыванием дробной части числа.
     Если левый операнд больше правого операнда, то операция диапазон возвращает пустой список. Подобную ситуацию можно отследить с помощью функции defined О, возвращающей истину, если ее параметр определен, или простой проверкой логической истинности массива, элементам которого присваивались значения с помощью операции диапазон:

$min = 2; .
$max = ~2;
Эаггау = ($min .. $max); # Массив не определен.
print "Эаггау array\n" if defined(@array); # Печати не будет!
print "Sarray array\n" if Эаггау; # Печати не будет!

Замечание
В операции диапазон можно использовать и отрицательные числа. В этом случае возвращается список отрицательных чисел, причем значение левого операнда должно быть меньше значения правого операнда:
(-5..5) # Список чисел: (-2, -1, О, 1, 2). (-5..-10) # Пустой список.

      Если операндами операции диапазон являются строки, содержащие буквенно-цифровые символы, то в списковом контексте эта операция возвращает список строк, расположенных между строками операндов с использованием лексикографического порядка:

@а = ("a".."d" ); # Массив @а: "а", "Ь", "с", "d"
@а = ("01".."31" ); # Массив @а: "01", "02", ... , "30", "31"
@а = ("al".."d4" ); # Массив Эа: "al", "a2", "аЗ", "а4"

      Если левый операнд меньше правого, с точки зрения лексикографического порядка, то возвращается единственное значение, равное левому операнду.

Замечание
Операция диапазон не работает со строками, содержащими символы национальных алфавитов. В этом случае она всегда возвращает единственное значение, соответствующее левому операнду.
     В скалярном контексте операция диапазон возвращает булево значение Истина или Ложь. Она работает как переключатель и эмулирует операцию запятая "," пакетного редактора sed и фильтра awk системы Unix, представляющую диапазон обрабатываемых строк этими программами.

      Каждая операция диапазон поддерживает свое собственное булево состояние, которое изменяется в процессе ее повторных вычислений по следующей схеме. Она ложна, пока ложным остается значение ее левого операнда. Как только левый операдц становится истинным, операция диапазон переходит в состояние Истина и находится в нем до того момента, как ее правый операнд не станет истинным, после чего операция снова переходит в состояние Ложь. Правый операнд не вычисляется, пока операция находится в состоянии Ложь; левый операнд не вычисляется, пока операция диапазон находится в состоянии Истина.

      В состоянии Ложь возвращаемым значением операции является пустая строка, которая трактуется как булева Ложь. В состоянии Истина при повторном вычислении она возвращает следующее порядковое число, отсчет которого начинается с единицы, т. е. как только операция переходит в состояние Истина, она возвращает 1, при последующем вычислении, если она все еще находится в состоянии Истина, возвращается 2 и т. д. В момент, когда операция переходит в состояние Ложь, к ее последнему возвращаемому порядковому числу добавляется строка "ко", которая не влияет на возвращаемое значение, но может быть использована для идентификации последнего элемента в диапазоне вычислений. Программа примера 4.12 и ее вывод, представленный в примере 4.13, иллюстрируют поведение оператора диапазон в скалярном контексте. Мы настоятельно рекомендуем внимательно с ними ознакомиться, чтобы "почувствовать", как работает эта операция.

#! peri -w
$left =3; # Операнд! $right =2; # Операнд2
# Заголовок таблицы
print "\$i\tflnana3OH\tOnepaHfll\tOnepaHfl2\n";
print '-' х 48, "\n\n";
# Тест операции
for($1=1; $i <= 10; $i++) {
$s = $left..$right;
print "$i\t $s\t\t $left \t\t $right\n";
$slO = 3 if $i==5; # Когда переменная цикла $i равна 5, # $slO устанавливается равной 3.
if ($right==0) {} else {—$right}; # Уменьшение $right на 1, пока
# $right не достигла значения 0.
—$left; }
     Сделаем замечания относительно работы программы примера 4..12. На первом шаге цикла левый операнд операции диапазон истинен, следовательно сама операция находится в состоянии Истина и возвращает первое порядковое число (i). Но правый операнд становится также истинным ($right = 2), следовательно она переходит в состояние Ложь и к возвращаемому ей значению добавляется строка "ЕО". На втором шаге цикла левый операнд истинен ($ieft = 2) и операция переходит в состояние Истина, возвращая значение д, к которому опять добавляется строка "ЕО", так как истинный правый операнд ($ right = 1) переводит операцию в состояние Ложь.
      На третьем шаге операция становится истинной ($ieft = 1), возвращая i, и правый операнд со значением Ложь ($right = о) не влияет на ее состояние. На следующих шагах 4 и 5 правый операнд остается ложным, а операция возвращает соответственно следующие порядковые числа 2 и з. На шаге 6 операция находится в состоянии Истина и возвращает 4, но правый операнд, принимая значение Истина ($right = о), переводит ее в состояние Ложь, в котором к возвращаемому значению добавляется строка "ЕО" и т. д.
      Подобное поведение, связанное с переходом из состояния Истина в состояние Ложь и одновременным изменением возвращаемого значения (добавлением строки "ЕО") эмулирует поведение операции запятая фильтра awk. Для эмуляции этой же операции редактора sed, в которой изменение возвращаемого значения осуществляется при следующем вычислении операции диапазон, следует вместо двух точек в знаке операции ".." использовать три точки "...".
Еще одно достаточно полезное свойство операции диапазон в скалярном контексте, используемое при обработке строк файлов, заключается в том, что если какой-либо операнд этой операции задан в виде числового литерала, то он сравнивается с номером прочитанной строки файла, хранящейся в специальной переменной $., возвращая булево значение Истина при совпадении и Ложь в противном случае. В программе примера 4.15 иллюстрируется такое использование операции диапазон. В ней осуществляется пропуск первых не пустых строк файла, печатается первая строка после пустой строки и после этого завершается цикл обработки файла.
#! peri -w
open{POST, "file.txt") or die "Нельзя открыть файл file.txt!";
LINE:
while(<POST>) {
$temp = 1../^$/; # Истина, пока строка файла не пустая.
next LINE if ($temp); # Переход на чтение новой строки,
# если $temp истинна.
print $_; # Печать первой строки файла после не пустой
last; # Выход из цикла
}
close(POST);
     В этой программе для нас интересен оператор присваивания возвращаемого значения операции диапазон переменной $temp. Прежде всего отметим, что эта операция используется в скалярном контексте, причем ее левый операнд представлен числовым литералом. На первом шаге цикла читается первая строка файла и специальной переменной $. присваивается ее номер 1, который сравнивается со значением левого операнда операции диапазон. Результатом этого сравнения является булево значение Истина, и операция диапазон переходит в состояние Истина, в котором она и остается, если первая строка файла не пустая, так как операция поиска по образцу / Л $/ возвращает в этом случае Ложь. Операция next осуществляет переход к следующей итерации цикла, во время которой читается вторая строка файла. Операция диапазон остается в состоянии Истина, если прочитанная строка файла пустая, увеличивая возвращаемое значение на единицу. Далее операция next снова инициирует чтение новой строки файла. Если строка файла пустая, то операция поиска по образцу возвращает значение Истина, переводя тем самым операцию диапазон в состояние Ложь, которое распознается при следующем ее вычислении, поэтому считывается еще одна строка файла (первая после пустой). Теперь операция next не выполняется, так как операция диапазон возвращает Ложь, печатается первая не пустая строка и операция last прекращает дальнейшую обработку файла.

Операция запятая
      Бинарная операция запятая "," ведет себя по-разному в скалярном и списковом контексте. В списковом контексте она является всего лишь разделителем между элементами списка:
@а = (1, 2); # Создается массив скаляров
# и его элементам присваиваются значения 1 и 2.

      В скалярном контексте эта операция полностью соответствует аналогичной операции языка С: вычисляется левый операнд, затем правый операнд, вычисленное значение которого и является возвращаемым значением этой операции. Если в предыдущем примере заменить массив @ а скалярной переменной $ а, то ей будет присвоено значение 2:

$а = (1, 2); # Переменной $а присваивается значение 2.

Замечание
Надеемся, читателю теперь стало ясно, почему конструкторы массивов, о которых мы рассказывали в гл. 3, в скалярном и в списковом контексте ведут себя по-разному.
      Для операции запятая в языке Perl существует удобный синоним — операция =>, которая полностью идентична операции запятая и удобна при задании каких-либо величин, которые появляются парами, например, ключ/значение в ассоциированных массивах. Правда, эта операция обладает еще одним свойством, достаточно удобным для ее использования при задании ассоциированных массивов: любой идентификатор, используемый в качестве ее левого операнда, интерпретируется как строка.

Операция выбора
Единственная тернарная операция выбора
операнд! ? операнд2 : операндЗ
полностью заимствована из языка С и работает точно так же, как и ее двойник. Если операнд! истинен, то возвращается значение операнд2, в противном случае операнда:
($n = 1) ? $а : Sarray;
     Скалярный или списковый контекст, в котором используется эта операция, распространяется и на возвращаемое значение этой операции:
$а = $yes ? $b : @b; tt Скалярный контекст. Если возвращается

# массив @Ь, то присваивается количество его t элементов.

       Операцию выбора можно использовать в качестве левого операнда операции присваивания, если и второй, и третий ее операнды являются правильными lvalue, т. е. такими значениями, которым можно присвоить какое-либо значение, например, именами переменных:

($а = $yes ? $b : @b) = @с;

       В связи с тем, что результатом операции выбора может оказаться правильное lvalue, следует использовать скобки для уточнения ее операндов. Например, если в следующем выражении

($а % 3) ? ($а += 2) : ($а -= 2);

опустить скобки вокруг операндов

$а % 3 ? $а += 2 : $а -= 2;

то оно будет откомпилировано следующим образом

(($а % 3) ? ($а += 2) : $а). -= 2;