Арифметические
операции
Язык программирования, предоставляя
возможность определения разнообразных типов данных, должен обеспечивать их обработку,
т. к. его основной целью является реализация алгоритмов обработки данных. Выполнение
допустимых действий над данными осуществляется с помощью набора определенных
в языке программирования операций. Операция — это выполнение определенного
действия над операндами, результатом которого является новое значение. С точки
зрения математики операцию можно рассматривать как некую функцию, которая по
заданным переменным (операндам) вычисляет новое значение. Все знают со школьной
скамьи четыре основных арифметических действия, выполняемых над числами: сложение
(+), вычитание (-), умножение (*) и деление (/). Эти действия (операции) мы
всегда выполняем над двумя числами (операндами), получая в результате новое
число. Язык программирования определяет не только арифметические операции над
числовыми данными, но и операции, применимые к другим допустимым типам данных.
Это могут быть операции над строками, массивами и т. д. Важно только одно, что
есть операция, определяемая своим знаком, и есть участвующие в ней операнды,
в совокупности позволяющие получить (вычислить) новое значение, которое может
принадлежать к одному из допустимых типов. В качестве операндов можно использовать
литералы, переменные и выражения, представляющие собой комбинации основных операций.
Общий синтаксис операции можно представить следующим образом:
операнд знак_операции операнд
Для некоторых операций один из операндов
может быть опущен. В этом случае операция называется одноместной или унарной,
например, вычисление противоположного по знаку значения операнда -$т. Если в
операции участвуют два операнда, то операция называется двуместной или бинарной.
Практически все допустимые операции являются унарными или бинарными, но в некоторых
современных языках программирования определена од-на-единственная условная тернарная
операция, требующая три операнда. Значением этой операции является второй или
третий операнд, в зависимости от истинности и ложности первого:
операнд_1 ? операнд_2 : операнд_3
Синтаксически выражение представляется в виде последовательности операндов
и знаков операций, которая обычно интерпретируется слева направо учетом порядка
старшинства операций, т. е. правил, определяющих, в какой последовательности
выполняются присутствующие в выражении операции. Для изменения порядка выполнения
используются круглые скобки. Результатом обработки интерпретатором выражения
является некоторое вычисленное значение, которое используется в других конструкциях
языка, реализующих алгоритм обработки данных.
В этой главе подробно рассматриваются
операции языка Perl и их использование при конструировании выражений. В языке
Perl определено несколько десятков операций. Их можно сгруппировать по типу
выполняемых действий (арифметические, побитовые, логические, отношения, присваивания),
на какие данные они воздействуют (строковые, списковые, файловые), и не относящиеся
ни к одному из перечисленных типов (операции запятая, ссылки, разыменования
и выбора). Следуя именно такой классификации операций языка Perl, мы и познакомим
с ними нашего читателя. Одни операции будут разобраны подробно, о других мы
только дадим общее представление, отнеся более детальное описание в другие главы
нашей книги.
Все арифметические операции
можно разбить на три группы: бинарные, унарные и увеличения/уменьшения.
Их основное назначение — выполнить определенные вычисления над числовыми данными,
но во всех арифметических операциях в качестве операндов могут выступать и строковые
данные, причем не обязательно, чтобы они конвертировались в числовые данные.
Бинарные арифметические операции
Бинарные арифметические операции
— это известные всем четыре арифметических действия: сложение (+), вычитание
(-), умножение (*) и деление (/), к которым добавляются еще два: остаток от
деления двух целых чисел (%) и возведение в степень (**). Примененные к числовым
данным или строковым, которые содержат .правильные литералы десятичных чисел,
они выполняют соответствующие арифметические действия (пример 4.1).
3.14 + 123; # Результат: 126.14
"3.14" + "123"; # Результат: 126.14
"3.14" + 123; # Результат: 126.14
"3.14" * 10; # Результат: 31.4
300 - 200; # Результат: 100
300 / 200; # Результат: 1.5
3 % 2; # Результат: 1
2 ** 3; . # Результат: 8
(-2) ** 3; # Результат: -8 '
2 ** (-3); # Результат: 0.125
2.5 ** 1.5; # Результат: -23.95284707521047
Как видим, бинарные арифметические операции "работают" именно так,
как мы привыкли их использовать в обычных арифметических вычислениях в нашей
повседневной жизни.
Замечание
Если операнд
в операции получения остатка от деления целых чисел (%) является вещественным
числом с дробной частью, то он преобразуется к целому простым отбрасыванием
дробной части, после чего операция выполняется над целыми числами.
Замечание
Нельзя
возводить отрицательное число не в целую степень. Если такое случается, то интерпретатор
не выдает никакой ошибки, но результатом такой операции является нуль: (-2.5)
** (1.3) = о.
В качестве операндов бинарных
арифметических операций можно использовать строки, не содержащие правильные
числовые литералы. В этом случае интерпретатор попытается выделить, начиная
с первого символа, из содержимого строки число и использовать его в качестве
соответствующего операнда заданной операции. Если не удается выделить правильный
числовой литерал, то операнд принимает значение, равное о. Подобные ситуации
демонстрируются в примере 4.2.
"3fl4" •+ "12-30";
# Результат: 15 ("3" + "12")
"а!20" + "12-30"; # Результат: 12 ("О" + "12")
."а!20" + "-0012-30"; # Результат: -12 ("О" +
"-12")
Замечание
Если установить
режим отображения предупреждающих сообщений интерпретатора (ключ -w), то при
попытке использовать в бинарных арифметических операциях строки, не содержащей
правильные числовые литералы, будет отображено сообщение вида:
Argument "al20" isn't
numeric in add at D:\EXAMPLE1.PL line 2.
Бинарные арифметические операции выполняются в скалярном контексте. Это означает,
что операндами должны быть скалярные переменные, а переменные массивов скаляров
и хеш-массивов принимают значения, равные, соответственно, количеству элементов
массивов скаляров или количеству использованных в хеш-таблице записей в соответствии
с требованиями скалярного контекста (пример 4.3).
@m = (2, 4, 6, 8, 10) ;
%ml = ( 1 => "а", 2 => "Ь"};
$n = 100;
$n + @m; # Результат: 105 (100 + 5)
@m + %ml; # Результат: 7 (5+2)
Замечание
В скалярном контексте хеш-массив принимает строковое значение,
состоящее из числа использованных участков записей в хеш-таблице и числа выделенных
участков записей, разделенных символом "/" (см. главу 3).
Используемое в арифметических операциях число получается выделением из этой
строки числового литерала, который как раз и соответствует количеству использованных
в хеш-таблице записей.
Унарные арифметические операции
В языке Perl есть только две унарные
арифметические операции (+) и (-). Унарный плюс +, примененный к данным любого
типа, представленным литералами или своими переменными, не имеет никакого семантического
эффекта. Он полезен перед выражением в круглых скобках, стоящим непосредственно
после имени функции, если необходимо чисто визуально акцентировать тот факт,
что функция фактически является списковой операцией.
Унарный минус (-) выполняет арифметическое отрицание числового операнда. Это
означает, что если число было отрицательным, то оно станет положительным, и
наоборот. Если операндом является идентификатор, то результатом выполнения этой
операции будет строка, состоящая из символа "-", за которым следует
идентификатор. Если операндом является строка, начинающаяся с символа минус
или плюс, то результатом также будет строка, в которой минус заменен на плюс
и наоборот. Для строк, не начинающихся с плюса или минуса, операция унарного
минуса добавляет его первым символом в строку. Все перечисленные случаи употребления
унарного минуса показаны в примере 4.4.
-'12.09'; # Результат: -12.09
-(-12.09);•# Результат: 12.09
-id; # Результат: '-id'
-'+id"; # Результат: '-id'
-"-id"; # Результат: "+id"
-'а!20'; # Результат: '-а!20'
Операции увеличения и уменьшения
Операции увеличения (++) и уменьшения
(--) аналогичны таким же операциям в языке С. (Авторы языка Perl не скрывают,
что они многое заимствовали из этого языка.) Результат этих операций зависит
от того, стоят ли они перед (префиксная форма) или после переменной (постфиксная
форма). При использовании префиксной формы они, соответственно, увеличивают
или уменьшают числовое значение переменной на единицу до возвращения значения.
Постфиксная форма этих операций изменяет числовое значение переменной после
возвращения ими значения. Действие этих операций на числовые переменные иллюстрируется
примером 4.5 (операторы фрагмента программы выполняются последовательно).
$n = 10.7; # Начальное значение
$infl = —$n; # Результат:
$infl = 9.7и$n=9.7
$inf2 = ++$n; # Результат: $inf2
= 10.7 и $n = 10.7
$postl = $n--; # Результат: $postl
= 10.7 но $n= 9.7
$post2 = $n++; # Результат: $post2
= 9.7 но $n= 10.7
Операция увеличения (префиксная и постфиксная), примененная к переменной, содержащей
строку определенного вида, выполняется несколько необычно. Если строка состоит
только из латинских букв, то возвращаемым значением операции увеличении будет
строка, в которой последняя буква заменена на следующую по порядку букву алфавита,
причем строчная заменяется строчной, а прописная прописной. Если строка завершается
идущими подряд буквами "z" или "z", то все они заменяются
соответственно на "а" или "А", а стоящая перед ними в строке
буква заменяется на следующую букву алфавита. Если вся строка состоит из букв
"z" и "z", то кроме замены этих букв в соответствии с
предыдущим правилом, перед ними добавляется строчная или прописная буква
"а" в зависимости от того, строчная или прописная буква "z"
стояла первой в строке.
Аналогичные действия осуществляются, если строка завершается последовательностью
цифр: последняя цифра увеличивается на единицу. Если строка завершается идущими
подряд цифрами 9, то все они заменяются на о, а примыкающий к ним символ "увеличивается"
на единицу: для буквы он переходит в следующий по алфавиту, а для цифры в следующую
по порядку цифру. Если последовательность целиком состоит из девяток, то все
они заменяются на нули, перед которыми добавляется единица. Префиксная и постфиксная
формы операции действуют как обычно. Несколько иллюстраций этих операций представлены
в примере 4.6.
$s = "abc"
$sl = ++$s; # Результат: $sl = "abd"
$s = "abC";
$sl = ++$s; # Результат: $sl = "abD"
$s = "abz";
$sl = ++$s; # Результат: $sl = "аса"
$s = "abzZz";
$sl = ++$s; # Результат: $sl = "acaAa"
$s = "ab09";
$sl = ++$s; # Результат: $sl = "ablO"
$s = "99"; .
$sl = ++$s; # Результат: $sl = "100"
Замечание
Операция уменьшения (—) работает со специальными строками
так же, как и с обычными. Осуществляется попытка выделить числовой литерал,
начиная с первого символа. Если такое оказывается возможным, то числовое значение
строки приравнивается выделенному числовому литералу, если нет — ее значение
считается равным 0. После этого применяется операция уменьшения к вычисленному
числовому значению строки
Операции конкатенации и повторения
Бинарная операция конкатенации,
или соединения объединяет два строковых операнда в одну строку.
Знаком этой операции служит точка ".":
"one_string"."two_string"; # Результат: "one_stringtwo_string"
В новой строке содержимое первого операнда и содержимое второго операнда соединяются
без пробела между ними. Обычно эта операция используется для присваивания переменной
некоторого нового значения. Если необходимо соединить две или более строки со
вставкой пробелов между ними, то следует воспользоваться операцией join (см.
гл. 10 "Работа со строками"). Можно, однако, для соединения строк
со вставкой пробела (или любого другого символа между ними) воспользоваться
свойством подстановки значения скалярной переменной в строку, ограниченную двойными
кавычками: $sl = "one_string"; $s2 = "two_string"; $s =
"$sl $s2"; # Значение $s: "one_string two_string"
Можно использовать операцию конкатенации строк последовательно в одном выражении
для соединения нескольких строк:
$sl = "one";
$s2 = "two";
$s3 = "three";
$s = $sl.$s2.$s3; # Значение $s: "onetwothree"
Операцию конкатенации можно применять и к числовым литералам, и к числовым данным,
хранящимся в скалярных переменных. Результатом будет строка, содержащая символьные
представления двух чисел:
$nl = 23.5;
$n2 = Зе01;
$n = $nl.$n2; t Значение $n: "23.530"
$n = 23.5.3е01; # Значение $n:'"23.530"
Заметим, что последний оператор выглядит несколько экзотично и его семантика
не определяется с первого взгляда.
Для работы со строками в языке Perl предусмотрена еще одна операция — повторение
строки х (просто символ строчной буквы "х"). Эта бинарная операция
создает новую строку, в которой строка, заданная левым операндом, повторяется
определяемое правым операндом количество раз:
"аА" х 2; # Результат: "аАаА"
10.0 х "3"; # Результат: "101010"
101е-1 х 3; # Результат: "101010" $n = 010;
$n х 2; # Результат: "88"
10.1 х 3.9; # Результат: "10.110.110.1"
"101е-1" х 2; # Результат: "101е-1101е-1"
Обратим внимание, что в качестве левого операнда можно использовать и числовые
литералы, и переменные, содержащие числовые данные. Правым операндом, задающим
число повторений, может быть любое число или строка, содержащая правильное десятичное
число.
Эта операция удобна, если надо напечатать или отобразить на экране монитора
повторяющийся символ или последовательность символов. Например, следующий оператор
выведет на экран монитора строку, целиком состоящую из символов подчеркивания:
print "_" х 80;
Левым операндом этой операции может быть список, заключенный в круглые скобки.
В этом случае операция повторения х работает как повторитель списка, т. е. ее
результатом будет список, в котором список левого операнда повторяется заданное
правым операндом количество раз:
(1) х 3; # Результат: (1, 1, 1) (1, 2) х 2; # Результат: (1, 2, 1, 2)
Это пример использования операции Perl в разных контекстах: скалярном и списковом
(о контекстах мы поговорим ниже в этой же главе). Операция повторения в списковом
контексте удобна для задания массива скаляров с одинаковыми значениями элементов
или групп элементов:
@аггау = ("а", "b") х 2; # Результат: Оаrrау = ("а",
"Ь", "а", "Ь") @аrrау = ("а") х 3; #
Результат: @аrrау = ("а", "а", "а")
Аналогично, эту операцию можно использовать для инициализации хеш-массива одинаковыми
значениями:
@keys = ( one, two, three); # Определение ключей хеш-массива. @hash{@keys} =
("а") х @keys; # Инициализация значений хеш-массива.
В последнем операторе присваивания в правой части массив скаляров @keys используется
в списковом контексте и представляет список своих значений, тогда как в левой
части он используется в скалярном контексте и имеет значение, равное числу своих
элементов.
Знак операции повторения х 'следует отделять пробелами от операндов, так как
иначе он может быть воспринят интерпретатором, как относящийся к лексеме, а
не представляющий операцию повторения. Например, при синтаксическом разборе
строки
$nx$m;
интерпретатор определит, что в ней идут подряд две переменные $nх и $m, a не
операция повторения содержимого переменной $п, что приведет к синтаксической
ошибке.
Операции отношения
Для сравнения скалярных данных или
значений скалярных переменных язык Perl предлагает набор бинарных операций,
вычисляющих отношения равенства, больше, больше или равно и т. п. между своими
операндами, поэтому эту группу операций еще называют операциями отношения.
Для сравнения числовых данных и строковых данных Perl использует разные
операции. Все они представлены в табл. 4.1.
Таблица 4.1. Операции отношения
Операция |
Числовая
|
Строковая
|
Значение
|
Равенство
|
==
|
eq
|
Истина,
если операнды равны, иначе ложь |
Неравенство
|
!=
|
ne
|
Истина,
если операнды не равны, иначе ложь |
Меньше
|
<
| lt
|
Истина,
если левый операнд меньше правого, иначе ложь |
Больше
|
> |
gt
|
Истина,
если левый операнд больше правого, иначе ложь |
Меньше
или равно |
<=
| le
|
Истина,
если левый операнд больше правого или равен ему, иначе ложь |
Больше
или равно |
>= |
ge
|
Истина,
если правый операнд больше левого или равен ему, иначе ложь |
Сравнение
|
<=>
|
cmp
|
0, если
операнды равны
1, если левый операнд больше правого
-1, если правый операнд больше левого |
Результатом операций отношения
(кроме последней сравнения) является Истина, значение 1, или Ложь, пустая строка
"".
Замечание
Значение истина в арифметических операциях интерпретируется как число
1, а в строковых как строка "1". Значение ложь в арифметических операциях
интерпретируется как число 0, а в строковых как пустая строка " ".
Числовые операции отношения
Числовые операции отношения применяются
к числовым данным, причем один или оба операнда могут задаваться строкой, содержащей
правильное десятичное число. Если в числовых операциях отношения какой-либо
из операндов задан строкой, содержимое которой не представляет правильное десятичное
число, то его значение принимается равным о и отображается предупреждение о
некорректном использовании операнда в числовой операции отношения (если включен
режим отображения предупреждений интерпретатора Perl). Смысл операций отношения
для числовых данных соответствует обычным математическим операциям сравнения
чисел (пример 4.7).
123 > 89; # Результат: 1 (истина)
123 < 89; # Результат: "" (ложь)
123 <= 89; # Результат: "" (ложь)
89 <= 89; # Результат: 1 (истина)
23 >= 89; # Результат: "" (ложь)
23 <=> 89; # Результат: -1 (правый операнд больше левого)
89 <=> 23; # Результат: 1 (правый операнд больше левого)
Применение числовых операций сравнения не представляет сложности, однако при
сравнении на равенство десятичных чисел с плавающей точкой могут проявиться
эффекты округления, связанные с ограниченным количеством значащих цифр в мантиссе
представления действительных чисел в компьютере и приводящие к "неправильной",
с точки зрения пользователя работе операций сравнения. Пример 4.8 иллюстрирует
подобную ситуацию.
#! peri -w
$z = 0.7;
$zz =• 10+0.7-10; # Переменная $zz содержит число 0.7
# Печать строки "z равно zz", если равны значения переменных $z и
$zz print "z равно zz\n" if ($z == $zz);
При попытке выполнить пример 4.8 мы с удивлением обнаружим, что наша программа
ничего не напечатает. В чем же дело? Разгадка лежит в операторе вычисления значения
переменной $zz. При выполнении арифметических операций в результате ошибок округления
получается значение 0.699999999999999 (можете вставить оператор печати переменной
$zz и убедиться в этом), хотя и близкое к 0.7, но не равное ему в точности.
Следовательно, операция сравнения отработала верно!
Совет
Не используйте операцию сравнения
на равенство вещественных чисел, ее результат может не соответствовать ожидаемому
с точки зрения математики. Если необходимо проверить равенство двух вещественных
чисел, то лучше сравнивать абсолютное значение их разности с некоторым очень
маленьким числом (в зависимости от требуемой точности):
abs($a-$b) <= 0.00000001; #
Проверка равенства
Строковые операции отношения
Сравнение строковых данных базируется
на их упорядочении в соответствии с таблицей кодов ASCII, т. е. символ с меньшим
кодом ASCII предшествует символу с большим кодом. Сравнение строк осуществляется
посимвольно слева направо. Это означает, что если равны первые символы строк,
то сравниваются вторые и если они равны, то сравниваются третьи и т. д. Причем,
если строки разной длины, то в конец строки меньшей длины добавляется недостающее
для равенства количество символов с кодом о. Следует отметить, что в отличие
от некоторых других языков программирования в Perl замыкающие строку пробельные
символы являются значимыми при сравнении строк. В примере 4.9 показаны сравнения
строк, иллюстрирующие изложенные правила.
"A" It "a"; |
# Результат: истина (код "А" - \101, код "а" - \141)
|
"a" It "aa";
|
# Результат: истина (к строке "а" добавляется символ
# с кодом \000,
который меньше кода \141
# второго символа
"а" строки правого операнда) |
"a" It "a
"; |
# Результат: истина (к строке "а" добавляется символ
# с кодом \000,
который меньше кода \040
# замыкающего пробела
строки правого операнда) |
"12" It "9"; |
# Результат: истина
(код "1" - \061, код "9" - \071) |
" 9" eq "09"; |
# Результат: ложь
(код " " - \040, код "О" - \060) |
Обратим внимание на две последние
операции сравнения строковых литералов. Содержимое их операндов может быть преобразовано
в правильные числа, и поэтому к ним применимы аналогичные числовые операции
отношения. Однако их результат будет существенно отличаться от результата выполнения
строковых операций отношения. При использовании операции < в предпоследнем
выражении результат будет Ложь, а если в последнем выражении применить операцию
==, то результат будет Истина. Об этом всегда следует помнить, так как Perl
автоматически преобразует символьные данные в числовые там, где это необходимо.
Логические операции
Рассмотренные в предыдущем параграфе
операции сравнения используются в условном операторе if (о нем и других операторах
Perl в следующей главе) для организации ветвления в программе. Однако, иногда
желательно проверять одновременно результаты нескольких операций сравнения и
предпринимать соответствующие алгоритму действия. Можно подобную ситуацию запрограммировать
с помощью вложенных операторов if, а можно в одном операторе использовать сложное
выражение, результатом вычисления которого будет, например, истинность двух
или более каких-либо операций сравнения. Для формирования подобных проверок
и служат логические операции языка Perl.
В языке определены бинарные операции
логического сравнения | 1 (ИЛИ), s & (И) и унарная операция логического
отрицания !. Их действие аналогично действию соответствующих математических
операций исчисления предикатов. Результатом операции | | (логическое ИЛИ) является
Истина, если истинен хотя бы один из операндов, в остальных случаях она возвращает
Ложь (остальные случаи представляют единственный вариант, когда оба операнда
ложны). Операция логического И && возвращает в качестве результата Истину,
только если оба операнда истинны, в противном случае ее результат Ложь. Операция
логического отрицания ! работает как переключатель: если ее операнд истинен,
то она возвращает Ложь, если операнд имеет значение Ложь, то ее результатом
будет Истина.
Замечание
В языке Perl нет специальных литералов для булевых
значений Истина и Ложь. В качестве значения Истина принимается любое скалярное
значение, не равное нулевой строке "" или числу 0 (а также его строковому
эквиваленту "О"). Естественно, нулевая "" строка и о (вместе
с его строковым эквивалентом "О") представляют значение Ложь.
Начиная с Perl 5.001, в язык были
введены логические операции or, and, not и хог. Первые три полностью аналогичны
логическим операциям | |, && и !, тогда как операция хог реализует исключающее
ИЛИ:
Истина хоr Истина = Ложь
Истина хоr Ложь = Истина
Ложь хоr Истина = Истина
Ложь хоr Ложь = Ложь
Единственное отличие этих логических операций от рассмотренных ранее заключается
в том, что они имеют наименьший приоритет при вычислении сложных выражений.
В Perl вычисление логических операций
ИЛИ и И осуществляется по "укороченной схеме". Это непосредственно
связано со смыслом этих операций. Если при вычислении операции ИЛИ определено,
что значение ее первого операнда Истина, то при любом значении второго операнда
результатом всей операции будет Истина, поэтому нет смысла вообще вычислять
второй операнд. Аналогично для операции логического И: если значение первого
операнда Ложь, то результат всей операции Ложь вне зависимости от значения второго
операнда. В отличие от операций отношения, результатом которых может быть о
(или пустая строка "") или 1, соответствующие булевым значениям Ложь
и Истина, результатом логических операций является значение последнего вычисленного
операнда. Пример 4.10 иллюстрирует вычисление логических операций.
$opl = 0; $ор2 = "s"; $орЗ = ""; $ор4 = 25; $ор5
= "0";
$ор4 II $ор2; # Результат: истина.
Значение: 25.
$ор2 I| $ор4; # Результат: истина.
Значение: "s".
$opl && $ор2; # Результат:
ложь. Значение: 0.
$ор2 && $ор4; # Результат:
истина. Значение: 25.
!$ор2; # Результат: ложь. Значение:
"".
not $орЗ; # Результат: истина.
Значение: 25.
$ор4 and $op5; # Результат: ложь.
Значение: "".
Свойство логических операций языка Perl вычисляться по "укороченной схеме"
можно использовать для управления некоторыми исключительными ситуациями, возникающими
в программе в процессе вычислений. Например, можно достаточно элегантно избежать
деления на нуль с помощью операции логического ИЛИ:
($х = 0) II ($т = 1/$х);
При вычислении результата этой операции сначала вычисляется левый операнд, который
сравнивает значение переменной $х с нулем. Если это значение действительно равно
нулю, то результатом операции сравнения будет Истина, а поэтому второй операнд
операции логического ИЛИ не вычисляется, так его значение не влияет на результат
выполнения логической oпeрации, и не возникает ситуации
деления на нуль. Если значение переменной $х не равно нулю, то результатом вычисления
первого операнда операции | | будет Ложь, и обязательно будет вычисляться ее
второй операнд, в котором осуществляется деление на не равную нулю переменную
$х.
Побитовые операции
Данные в компьютере представляются
в виде последовательности битов. В языке Perl определены бинарные операции
побитового логического сравнения целых чисел и строк: & (И), | (ИЛИ)
и л (исключающее ИЛИ), а также унарная операция логического отрицания
~. Результат их вычисления зависит от того, к данным какого типа они применяются:
числовым или строковым. Эти операторы различают числовые данные и строки, содержимое
которых может быть преобразовано в число.
Кроме логических операций побитового
сравнения, две операции сдвигают влево («) и вправо (») биты в представлении
целых чисел. Эти операторы не работают со строками.
Числовые операнды
Если хотя бы один операнд в бинарных
побитовых операциях является числом, то содержимое второго операнда
также должно быть числом. Операнд, являющийся строкой символов, преобразуется
в числовое значение. В случае несоответствия содержимого строки десятичному
числу ее значение принимается равным о и отображается предупреждающее сообщение,
если установлен соответствующий режим работы интерполятора. Все числовые операнды
преобразуются к целым числам простым отбрасыванием дробной части, никакого округления
не происходит.
Чтобы понять сущность побитовых
операций над числовыми данными, необходимо представлять, как хранятся в программе
целые числа. При задании чисел мы можем использовать одно из трех представлений:
десятичное, восьмеричное или шестнадцатеричное. Однако в компьютере числа не
хранятся ни в одном из указанных представлений. Они переводятся в двоичные числа
— числа с основанием 2, цифры которых и называются битами. Двоичные числа представляют
собой запись чисел в позиционной системе счисления, в которой в качестве основания
используется число 2. Таким образом, двоичные цифры, или биты, могут принимать
значения только о или 1. Например, десятичное число ю, переведенное в двоичное,
представляется в виде loio. Для обратного перевода этого числа в десятичную
форму представления следует, в соответствии с правилами позиционной системы
счисления, произвести следующие действия:
1 * (2**3) + 0 * (2**2) + 1 * -(2**1) + 0 * (2**0)
Язык Perl гарантирует, что все целые числа имеют длину 32 бит, хотя на некоторых
машинах они могут представляться и 64 битами. Именно с двоичными представлениями
целых чисел и работают все побитовые операции, преобразуя и отрицательные, и
положительные числа к целому типу данных.
Операция & побитового логического И сравнивает каждый бит правого операнда
с соответствующим битом левого операнда. Если оба сравниваемых бита имеют значение
1, то соответствующий бит результирующего значения операции устанавливается
равным 1, в противном случае значением бита результата будет о. В качестве примера
рассмотрим следующее выражение
45.93 & 100
Прежде всего, правый операнд преобразуется к целому 45, двоичное представление
которого будет
00000000000000000000000000101101
Двоичное представление левого операнда юо будет иметь вид
00000000000000000000000001100100
Результатом побитового логического И будет следующая последовательность битов
00000000000000000000000000100100
Она соответствует десятичному целому числу 36. Следовательно, значением выражения
45.93 & юо будет целое число 36.
Замечание
В этом примере мы специально использовали
32-битное представление целых чисел, хотя для бинарных побитовых операций лидирующие
нули не имеют значения. Они существенны только при операциях побитового логического
отрицания и сдвигов.
При побитовой операции логического
ИЛИ | бит результата устанавливается равным 1, если хотя бы один из сравниваемых
битов равен 1. Операция побитового логического ИЛИ для тех же двух чисел
45.93 | 100
даст результат равный юэ, так как при применении побитового логического ИЛИ
к операндам
00000000000000000000000000101101 (десятичное 45)
И
00000000000000000000000001100100 (десятичное 100)
дает следующую цепочку битов
00000000000000000000000001101101 (десятичное 109:
2**6+2**5+2**3+2'**2+2**1)
Побитовое исключающее ИЛИ при сравнении битов дает значение
\ тогда, когда точно один из операндов имеет значение равное 1.
Следовательно, 1 ^ 1=о и о ^ о=о, в остальных случаях
результат сравнения битов равен о. Поэтому для тех же чисел результатом операции
будет десятичное число 73.
Операция логического отрицания ~ является унарной и ее действие заключается
в том, что при последовательном просмотре битов числа все значения о заменяются
на 1, и наоборот. Результат этой операции существенно зависит от используемого
количества битов для представления целых чисел. Например, на 32-разрядной машине
результатом операции ~1 будет последовательность битов
11111111111111111111111111111110
представляющая десятичное число 42949б7294=2 31 +2 30
+...+2 1 , тогда как на 16-разрядной машине эта же операция даст
число б534=2 31 +2 30 +...+2 1 .
Бинарные операции побитового сдвига осуществляют сдвиг битов целого числа, заданного
левым операндом, влево («) или вправо (») на количество бит, определяемых
правым целочисленным операндом. При сдвиге вправо недостающие старшие биты,
а при сдвиге влево младшие биты числа дополняются нулями. Биты, выходящие за
разрядную сетку, пропадают. Несколько примеров операций сдвига представлено
ниже:
# Битовое представление числа 22: (00000000000000000000000000010110)
22 » 2 # Результат: (00000000000000000000000000000101) = 5
22 << 2 # Результат: (00000000000000000000000001011000)
= 88
Все перечисленные операции работают и с отрицательными целыми числами, только
при их использовании следует учитывать, что они хранятся в дополнительном коде.
Двоичная запись неотрицательного целого числа называется прямым кодом. Обратным
кодом называется запись, полученная поразрядной инверсией прямого кода. Отрицательные
целые числа представляются в памяти компьютера в дополнительном коде, который
получается прибавлением единицы к младшему разряду обратного кода. Например,
представление числа -1 получается следующим образом:
00000000000000000000000000000001 # положительное число 1 111111111111111111111111111111Ю
# обратный код числа 1 11111111111111111111111111111111 # добавляем к младшему
разряду 1
# и получаем представление числа
-1
Именно с этим кодом числа -i будут работать все побитовые операции, если оно
будет задано в качестве операнда одной из них.
Внимание
В языке Perl, как отмечалось в
гл. 3, в арифметических операциях используется представление всех чисел в виде
чисел с плавающей точкой удвоенной точности. Там же говорилось, что целое число
можно задавать с 15 значащими цифрами, т.е. максимальное положительное целое
число может быть 999 999 999 999 999. Но это число не имеет ничего общего с
представлением целых чисел в компьютере, для которых может отводиться
64, 32 или 16 битов, в зависимости от архитектуры компьютера. Во всех побитовых
операциях можно предсказать результат только если операндами являются целые
числа из диапазона -2 32 -1. . 2 32 -1, так как ясен
алгоритм их представления. Вещественные числа, не попадающие в этот диапазон,
преобразуются к целым, но алгоритм их преобразования не описан авторами языка.
Строковые операнды
Если оба операнда являются
строковыми литералами или переменными, содержащими строковые данные, то операции
побитового логического сравнения сравнивают соответствующие биты кода каждого
символа строки. Для кодирования символов используется таблица ASCII-кодов. Если
строки разной длины, то при сравнении полагается, что строка меньшей длины содержит
необходимое число недостающих символов с восьмеричным кодом \ооо. Например,
результатом сравнения двух строк "++" и "з" с помощью операции
| побитового логического ИЛИ будет строка ",-+". Операнды этой операции
представляются следующими битовыми последовательностями (каждый символ представляется
8 битами):
00101011 00101011 # Восьмеричный код символа "+" равен 053. 00110011
# Восьмеричный код символа "3" равен 063.
Вторая строка дополняется восемью нулевыми битами и последовательно для каждой
пары соответствующих бит двух строк одинаковой длины выполняется операция логического
ИЛИ. Результатом выполнения этой процедуры является битовая последовательность
00111011 00101011
При ее интерпретации как строки символов получается последовательность двух
символов с восьмеричными кодами 07 3 и 053, которые соответствуют символам ";"
и "+"
Следует отметить, что в случае двух строковых операндов, содержимое которых
можно преобразовать в числовые данные, подобное преобразование не происходит,
и побитовые операции логического сравнения выполняются как с обычными строковыми
данными:
45.93 I 100 # Результат: число 109.
"45.93" I 100 # Результат: число 109.
45.93 I "100" # Результат: число 109.
"45.93" I "100" # Результат: строка "55>93".
В первых трех операциях этого примера строки преобразуются в числа, а потом
выполняется соответствующая операция побитового логического ИЛИ двух чисел.
Выполнение операции побитового логического отрицания ~ для строки ничем не отличается
от соответствующей операции отрицания для чисел с той лишь разницей, что применяется
она к битовому представлению символов строки:
~"1" # Результат: "+".
~"ab" t Результат: "ЮЭ".
Операции присваивания
Присваивание переменной какого-либо
значения, определенного литералом, или присваивание одной переменной значения
другой переменной является наиболее часто выполняемым действием в программе,
написанной на любом языке программирования. В одних языках это действие определяется
с помощью оператора, а в других — с помощью операции. Отличие заключается в
том, что в языках, где присваивание является операцией, оно может использоваться
в выражениях как его составная часть, так как любая операция вычисляет определенное
значение, тогда как оператор всего лишь производит действие. В языке Perl присваивание
является операцией, которая возвращает правильное lvalue. Что это такое,
мы разъясним буквально в следующих абзацах.
Операция присваивания =, с которой читатель уже немного знаком, является бинарной
операцией, правый операнд которой может быть любым правильным выражением, тогда
как левый операнд должен определять область памяти, куда операция присваивания
помещает вычисленное значение правого операнда. В этом случае и говорят, что
левый операнд должен быть правильным lvalue (от английского left value
— левое значение). А что мы можем использовать в программе для обозначения области
памяти? Правильно, переменные. Следовательно, в качестве левого операнда операции
присваивания можно использовать переменную любого типа или элемент любого массива.
(В языке Perl существуют и другие объекты, которые можно использовать в качестве
левого операнда операции присваивания, но об этом в свое время.) Следующая операция
простого присваивания $а = $Ь+3;
вычислит значение правого операнда и присвоит его переменной $а, т.е. сохранит
в области памяти, выделенной для переменной $а. Возвращаемым значением этой
операции будет адрес области памяти переменной $а (правильное lvalue),
или говоря проще, имя скалярной переменной $а, которое снова можно использовать
в качестве левого операнда операции присваивания. Таким образом, в языке Perl
следующая операция присваивания
($а = $Ь) = 3;
является синтаксически правильной и в результате ее вычисления переменной $а
будет присвоено значение з, так результатом вычисления операции присваивания
$а = $ь будет присвоение переменной $а значения переменной $ь, а возвращаемым
значением можно считать переменную $а, которой в следующей операции
присваивается значение з. Читатель спросит: "А зачем городить такие сложности,
если тот же самый результат можно получить простой операцией присваивания $а
= з?". Действительно, замечание справедливое. Но на этом примере мы показали,
как можно использовать операцию присваивания в качестве правильного lvalue.
Более интересные примеры мы покажем, когда определим составные операции
присваивания, заимствованные из языка С.
Синтаксические правила языка Perl позволяют осуществлять присваивание одного
и того же значения нескольким переменным в одном выражении:
$varl = $var2 = $varl[0] =34;
Очень часто при реализации вычислительных алгоритмов приходится осуществлять
разнообразные вычисления с использованием значения некоторой переменной и результат
присваивать этой же переменной. Например, увеличить на з значение переменной
$а и результат присвоить этой же переменной $а. Это действие можно реализовать
следующей операцией присваивания:
$а = $а+3;
Однако, язык Perl предлагает более эффективный способ решения подобных проблем,
предоставляя в распоряжение программиста бинарную операцию составного присваивания
+=, которая прибавляет к значению левого операнда, представляющего правильное
lvalue, значение правого операнда и результат присваивает переменной,
представленной левым операндом. Таким образом, оператор составного присваивания
$а += 3; I Результат: $а = $а+3
эквивалентен предыдущему оператору простого присваивания. Единственное отличие
заключается в том, что его реализация эффективнее реализации простого присваивания,
так как в составном операторе присваивания переменная $а вычисляется один раз,
тогда как в простом ее приходится вычислять дважды. (Под вычислением переменной
понимается вычисление адреса представляемой ею области памяти и извлечение значения,
хранящегося в этой области памяти.)
Для всех бинарных операций языка Perl существуют соответствующие составные операции
присваивания. Все они, вместе с примерами их использования, собраны в табл.
4.2.
Таблица 4.2. Составные операции присваивания
Операция |
Пример
|
Эквивалент
с операцией простого присваивания |
**=
|
$а **=
3; |
$а = $а
** 3; |
+=
|
$а +=
3; |
$а = $а
+ 3; |
-=
|
$а -=
3; |
$а = $а
- 3; |
.=
|
$а .=
"а"; |
$а = $а
. "а"; |
*=
|
$а *=
3; |
$а = $а
* 3; |
/=
|
$а /=
3; |
$а = $а
/ 3; |
%=
|
$а %=
3; |
$а = $а
% 3; |
х=
|
$а х=
3; |
$а = $а
х 3; |
&=
|
$а &=
$b; |
$а = $а
& $b; |
|=
|
$а |=
3; |
$а = $а
| 3; |
^=
|
$а ^=
3; |
$а = $а
^ 3; |
«=
|
$а «=
3; |
$а = $а
« 3; |
»=
|
$а »=
3; |
$а = $а
» 3; |
&&=
|
|
|
||=
|
$а ||=
$b == 0; |
$а = $а
|| $b == 0; |
Возвращаемым значением каждой
из составных операций присваивания, как и в случае простого присваивания, является
переменная левого Операнда (правильное lvalue), поэтому их можно использовать
в любом операнде других операций присваивания (пример 4.11).
$b = 1; |
|
$а = ($Ь +=3);
|
# Результат: $а =
$b = 4 |
$а += ($Ь += 3);
|
# Результат: $а =
$а+$b+3 |
( ($а += 2) **= 2)
-= 1; |
# Результат: $а =
($а+2)**2-1 |
Замечание
При использовании операции присваивания
(простой или составной) в качестве левого операнда другой операции присваивания
обязательно ее заключение в круглые скобки. Иначе может сгенерироваться синтаксическая
ошибка, или выражение будет интерпретировано не так, как задумывалось. При наличии
нескольких операций присваивания в одном выражении без скобок интерпретатор
peri начинает его разбор справа. Например, если последнее выражение
примера 4.11 записать без скобок
$а += 2 **= 2 -•= 1;
то при его синтаксическом анализе интерпретатор сначала выделит операцию присваивания
2 -= 1;
и сообщит об ошибке, так как ее синтаксис ошибочен (левый операнд не является
переменной или элементом массива).
Ссылки и операция разыменования
При выполнении программы Perl она,
вместе с используемыми ею данными, размещается в оперативной памяти компьютера.
Обращение к данным осуществляется с помощью символических имен — переменных,
что является одним из преимуществ использования языка высокого уровня типа Perl.
Однако иногда необходимо получить непосредственно адрес памяти, где размещены
данные, на которые мы ссылаемся в программе с помощью переменной. Для этого
в языке определено понятие ссылки, или указателя, который
содержит адрес переменной, т. е. адрес области памяти, на которую ссылается
переменная. Для получения адреса переменной используется операция ссылка, знак
которой "\" ставится перед именем переменной:
$m ='5;
$рт = \$m; f Ссылка на скалярную величину
Ссылки хранятся в скалярных переменных и могут указывать на скалярную величину,
на массив, на хеш и на функцию:
@аrrау = (1,2,3);
$раггау = \@аггау; # Ссылка на массив скаляров
%hesh = (опе=>1, two=>2, three=>3);
$phesh = \%hesh; § Ссылка на массив скаляров
Если распечатать в программе переменные-ссылки $pm, $parray и $phesh, то мы
увидим строки, подобные следующим:
SCALAR(Ox655a74) ARRAY (Ох655ЫО) HASH(0x653514)
В них идентификатор определяет тип данных, а в скобках указан шестнадцатеричный
адрес области памяти, содержащей данные соответствующего типа.
Для получения содержимого области памяти, на которую ссылается переменная-указатель,
требуется выполнить операцию разыменования ссылки. Для этого достаточно
перед именем такой переменной поставить символ, соответствующий типу данных,
на который ссылается переменная ($, @, %):
@keys = keys(%$phash); # Массив ключей хеша @values = values(%$phash); # Массив
значений хеша print "$$pm \n@$parray \n@keys \n@values";
Этот фрагмент кода для определенных в нем переменных-ссылок на скаляр, массив
и хеш напечатает их значения:
5 # Значение скалярной переменной $m
123 # Значения элементов массива скаляров @аrrау
three two one # Ключи хеша %hash
321 # Значения хеша %hash
Использование описанной выше простой операции разыменования может приводить
к сложным, трудно читаемым синтаксическим конструкциям при попытке получить
значения элементов сложных конструкций: массива массивов, массива хешей и т.
п. Для подобных целей в языке Perl предусмотрена бинарная операция ->, левым
операндом которой может быть ссылка на массив скаляров или хеш-массив, а правым
операндом индекс элемента массива или хеша, значение которого необходимо получить:
print "$parray->[0], .$parray->[1], .$parray->[2]\n"; print
"$phash->{one} r $phash->{two}, $phash->{three}\n";
Эти операторы напечатают значения элементов массива ©array и хеша %hash.
(Более подробно ссылки и операции разыменования рассматриваются в части
9.)
Операции связывания
Операции сопоставления с образцом,
используемые многими утилитами обработки текста в Unix, являются мощным средством
и в языке Perl. Эти операции с регулярными выражениями включают поиск (m//),
подстановку (s///) и замену символов (tr///) в строке. По умолчанию
они работают со строкой, содержащейся в системной переменной $_. Операции =~
и \ ~ связывают выполнение сопоставления с образцом над строкой, содержащейся
в переменной, представленной левым операндом этих операций: $_ = "It's
very interesting!";
s/very/not/; # Переменная $_ будет содержать строку
# "It's not interesting!"
$m = "my string";
$m =~ s/my/our/; i Переменная $m будет содержать строку
tt "our string"
Возвращаемым значением операции =~ является Истина, если при выполнении соответствующей
ей операции сопоставления с образцом в строке была найдена последовательность
символов, определяемая регулярным выражением, и Ложь в противном случае. Операция
! ~ является логическим дополнением к операции =~. Следующие два выражения полностью
эквивалентны:
$m !~ m/my/our/; not $m =~ m/my/our/;
(Более подробно регулярные выражения и операции связывания рассматриваются в
части 10.)
Именованные унарные операции
В языке Perl определено большое
количество встроенных функций, выполняющих разнообразные действия. Некоторые
из них, с точки зрения синтаксического анализатора языка, на самом деле являются
унарными операциями, которые и называют именованными унарными операциями, чтобы
отличить их от унарных операций со специальными символами в качестве знаков
операций (например, унарный минус "-", операция ссылки "\",
логического отрицания "!" и т. д.). Некоторые из именованных унарных
операций перечислены ниже:
chdir, cos, defined,
goto, log, rand, rmdir, sin, sqrt, do, eval, return (Является ли функция унарной
операцией, можно определить в приложении 1.)
К именованным унарным операциям относятся также все операции проверки файлов,
синтаксис которых имеет вид:
-символ [имя_файла\дескриптор_файла]
Например, для проверки существования файла определена операция -е, выяснить
возможность записи в файл можно операцией -w.
(Более подробно операции проверки файлов рассматриваются в части
7 щелкни
здесь.)
Операции ввода/вывода
Для взаимодействия и общения с внешним
окружением в любом языке программирования предусмотрены операции ввода/вывода.
Perl не является исключением. В нем определен ряд операций, обеспечивающих ввод
и вывод данных в/из программы.
Операция print
С этой операцией вывода мы уже немного
знакомы. Операция print — унарная операция, правым операндом которой служит
задаваемый список значений, которые она отображает по умолчанию на экране монитора.
Операцию, операндом которой является список, называют списковой операцией. Внешне
ее можно задать как вызов функции, заключив ее операнд в круглые скобки. Следующие
операции эквивалентны:
print "@m", "\n",
$m, "\n"; print("@m", "\n", $m, "\n");
(Более подробно эта операция рассматривается в части
6.)
Выполнение системных команд
Операция заключения в обратные кавычки
— это специальная операция, которая передает свое содержимое на выполнение операционной
системы и возвращает результат в виде строковых данных:
$command = ~dir"; # Переменная
$command после выполнения операционной . # системой KOMaHflbi'dir' содержит
результат ее # выполнения.
Содержимое строкового литерала
в обратных кавычках должно быть, после подстановки значений переменных, которые
могут в нем присутствовать, правильной командой операционной системы.
(Более подробно эта операция рассматривается в части
6.)
Операция <>
При открытии файла с помощью функции
open () одним из ее параметров является идентификатор, называемый дескриптором
файла, с помощью которого можно в программе Perl ссылаться на файл. Операция
ввода из файла осуществляется заключением в угловые скобки его дескриптора
<дескриптор_файла>. Результатом вычисления этой операции является строка
файла или строки файла в зависимости от скалярного или спискового контекста
ее использования. Следующие операторы иллюстрируют эту особенность данной операции:
open( MYFILE, "data.dat");
tt Открытие файла "data.dat" и назначение ему
# дескриптора MYFILE
$firstline = <MYFILE>; #
Присваивание первой строки файла @remainder = <MYFILE>; # Оставшиеся строки
файла присваиваются
# элементам массива скаляров.
Дескриптор файла можно использовать и в операции print, организуя вывод не на
стандартное устройство вывода, а в файл, представляемый дескриптором:
print MYFILE @m;
Особый случай представляет операция чтения из файла с пустым дескриптором о:
информация считывается либо из стандартного файла ввода, либо из файлов, заданных
в командной строке.
(Более подробно операции ввода/вывода из/в файл рассматриваются в
части 6.) (Работа с файлами более подробно рассматривается в
части 7.)
Разные операции
В этом параграфе собраны операции,
которые не вошли ни в одну из рассмотренных нами групп операций. Две из них
упоминались при описании массивов и хешей (операции диапазон и запятая), а третья
является единственной тернарной операцией языка Perl (операция выбора).
Операция диапазон
Бинарная операция диапазон
".." по существу представляет две различных операции в зависимости
от контекста, в котором она используется.
В списковом контексте,
если ее операндами являются числа (числовые литералы, переменные или выражения,
возвращающие числовые значения), она возвращает список, состоящий из последовательности
увеличивающихся на единицу целых чисел, начинающихся со значения, определяемого
левым операндом, и не превосходящих числовое значение, представленное правым
операндом. Операцию диапазон часто используют для задания значений элементов
массивов и хешей, а также их фрагментов (см. главу 3). Она удобна для
организации циклов for и f oreach:
# Напечатает числа от 1 до 5, каждое на новой строке, foreach $cycle (1..5){
print "$cycle\n"; }
# Напечатает строку "12345".
for(l..5){
print; '
}
(Операторы цикла рассматриваются в части 5.)
Замечание
Если значение какого-либо операнда
не является целым, оно приводится к целому отбрасыванием дробной части числа.
Если левый операнд больше правого
операнда, то операция диапазон возвращает пустой список. Подобную ситуацию можно
отследить с помощью функции 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, надеясь, что читатель сможет понять
их смысл. Если все же это окажется для него сложным, мы рекомендуем снова вернуться
к этой программе после прочтения главы 5.
$1 |
Диапазон
|
Операнд1
|
Операнд2
|
1 |
1ЕО |
3 |
2 |
2 |
1ЕО |
2 |
1 |
3 |
1 |
1 |
0 |
4 |
2 |
0 |
0 |
5 |
3 |
-1 |
0 |
6 |
4EO |
-2 |
2 |
7 |
1EO |
-3 |
1 |
8 |
1 |
-4 |
0 |
9 |
2 |
-5 |
0 |
10 |
3 |
-6 |
0 |
Сделаем замечания относительно
работы программы примера 4..12. На первом шаге цикла левый операнд операции
диапазон истинен, следовательно сама операция находится в состоянии Истина и
возвращает первое порядковое число (i). Но правый операнд становится также истинным
($right = 2), следовательно она переходит в состояние Ложь и к возвращаемому
ей значению добавляется строка "ЕО". На втором шаге цикла левый операнд
истинен ($ieft = 2) и операция переходит в состояние Истина, возвращая значение
д, к которому опять добавляется строка "ЕО", так как истинный правый
операнд ($ right = 1) переводит операцию в состояние Ложь.
На третьем шаге операция становится истинной ($ieft = 1), возвращая i, и правый
операнд со значением Ложь ($right = о) не влияет на ее состояние. На следующих
шагах 4 и 5 правый операнд остается ложным, а операция возвращает соответственно
следующие порядковые числа 2 и з. На шаге 6 операция находится в состоянии Истина
и возвращает 4, но правый операнд, принимая значение Истина ($right = о), переводит
ее в состояние Ложь, в котором к возвращаемому значению добавляется строка "ЕО"
и т. д.
Подобное поведение, связанное с переходом из состояния Истина в состояние Ложь
и одновременным изменением возвращаемого значения (добавлением строки "ЕО")
эмулирует поведение операции запятая фильтра awk. Для эмуляции этой же операции
редактора sed, в которой изменение возвращаемого значения осуществляется при
следующем вычислении операции диапазон, следует вместо двух точек в знаке операции
".." использовать три точки "...". Результаты вывода программы
примера 4.12, в которой осуществлена подобная замена, представлены в примере
4.14.
$i |
Диапазон
|
Операнд
1 |
Операнд2
|
1 |
1 |
3 |
2 |
2 |
2EO |
2 |
1 |
3 |
1 |
1 |
0 |
4 |
2 |
0 |
0 |
5 |
3 |
-1 |
0 |
6 |
4EO |
-2 |
2 |
7 |
1 |
-3 |
1 |
8 |
2 |
-4 |
0 |
9 |
3 |
-5 |
0 |
10 |
4 |
-6 |
0 |
Еще одно достаточно полезное свойство
операции диапазон в скалярном контексте, используемое при обработке строк файлов,
заключается в том, что если какой-либо операнд этой операции задан в виде числового
литерала, то он сравнивается с номером прочитанной строки файла, хранящейся
в специальной переменной $., возвращая булево значение Истина при совпадении
и Ложь в противном случае. В программе примера 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;
Списковые операции
Списковая операция — это
операция над списком значений, причем список не обязательно заключать в круглые
скобки.
Мы уже знакомы с одной из таких
операций — операцией вывода на стандартное устройство print. Иногда мы говорили
об этой операции как о функции — и это справедливо, так как все списковые
операции Perl выглядят как вызовы функций (даже их описание находится в разделе
"Функции" документации по Perl), и более того, они позволяют заключать
в круглые скобки список их параметров, что еще сближает их с функциями. Таким
образом, списковую операцию (или функцию) print можно определить в программе
любым из следующих способов:
print $a, "string", $b; # Синтаксис списковой операции, print($a,
"string", $b); # Синтаксис вызова функции.
(Встроенные функции более подробно рассматриваются в части
11.)
Замечание
Описание многих встроенных функций (списковых операций)
можно найти в главах, в которых вводятся понятия языка, для работы с которыми
и предназначены определенные встроенные функции. Например, функции print, printf
и write описаны в главе 6.
| |