Контекст

Основное предназначение языка программирования — обеспечить удобную и эффективную реализацию алгоритмов обработки информации, представленной в форме допускаемых языком типов данных. Для каждого типа данных определен набор операций, которые можно выполнять над ними. Операция определяет некоторое действие над величинами, которые называются ее операндами. В зависимости от числа требуемых для выполнения операции операндов различают унарные (один операнд), бинарные (два операнда) и тернарные (три операнда) операции. Общий синтаксис операции в любом процедурном языке программирования может быть представлен в виде
Операнд1 знак операнд2
Здесь знак представляет символ пли последовательность символов, используемых для обозначения соответствующей операции. Для унарных операций один из операндов должен быть опущен, тогда как для тернарных следует добавить еще один операнд. Обычно в языках программирования реализуется единственная тернарная операция — операция выбора, с которой хорошо знакомы программисты на языке С. Ее семантика такова: результатом ее выполнения является второй операнд, если первый операнд истинен, и третий операнд в противном случае. Синтаксис операции выбора имеет следующий вид:
Операнд1 ? операнд2 : операнд3
Операции используются для формирования выражений, которые вычисляются в процессе выполнения программы. Синтаксически выражение представляется в виде последовательности операндов и знаков операций, которая интерпретируется компилятором в определенную последовательность выполнения операций с учетом их старшинства — правил, определяющих, какая операция должна выполняться первой, второй и т. д. Для изменения порядка выполнения операций служат круглые скобки. Результатом выполнения выражения является некоторое вычисленное значение. Это и есть основное предназначение выражения — вычислять в программе некоторое значение на основе других известных значений.
В языке Perl определено несколько десятков операций, причем некоторые операции являются обычными с точки зрения любого языка — умножение, деление, вычитание и сложение целых и вещественных чисел, конкатенация строк и т. д. - и для их записи используется общепринятый синтаксис, а другие операции, например, операция чтения входного потока <>, представляют вызовы определенных в языке стандартных функций или являются действиями с внешними данными. Все операции языка можно разбить на три большие группы: скалярные, списковые и не принадлежащие к первым двум, причем в зависимости от используемых подтипов скалярных операндов (числа или строки) некоторые скалярные операции вычисляются по разным алгоритмам.
Каждая операция формирует для своих операндов определенный контекст, в котором они должны вычисляться, причем контекст одного операнда операции может зависеть от типа другого операнда, как в случае, например, с операцией присваивания. Поэтому, прежде чем переходить к подробному изучению операций языка Perl, мы расширим наше представление о контексте — понятии, широко используемом в этом языке.

Контекст

Все вычисления в языке Perl осуществляются в определенном контексте, который влияет на интерпретацию результатов вычисления выражений и на процесс вычисления операций в них. Контекст можно представить себе как некоторое окружение, в котором выполняется операция и интерпретируется ее значение. Мы уже знаем два основных контекста: скалярный и списковый. Идея контекста заключается в том, что если в данном месте выполнения некоторой операции требуется скалярное значение, то операция вернет именно скаляр, а если список (несколько значений) — то именно список и будет результатом ее выполнения, даже если он будет представлен единственным скалярным значением. Это очень похоже на то, как употребляются некоторые английские слова, у которых единственное и множественное число не различаются и имеют одинаковое написание, например «sheep» (овца) или «fish» (рыба). Единственный способ понять, употреблены они в единственном или множественном числе, — это контекст предложения. С точки зрения современных концепций языков программирования реализация контекста для операций Perl осуществляется с помощью механизма перегрузки: в зависимости от того, какой тип данных операция должна вернуть в соответствующем контексте, для ее выполнения вызываются разные функции.
Операция в зависимости от контекста, в котором она вычисляется, может определять контекст вычисления своих операндов. Например, операция substr выделения подстроки (чуть позже мы узнаем, что каждая стандартная функция Perl может рассматриваться как операция, используемая в выражениях) «создает» для своих операндов скалярный контекст. Поэтому операция чтения из входного потока <STDIN&, использованная в качестве параметра указанной операции выделения подстроки, будет выполняться в скалярном контексте: substr(<STDIN>, 0, 1);
А это приведет к тому, что она будет читать только одну строку из входного потока, реализуя скалярный контекст для своего операнда.
Эта же операция чтения из стандартного потока <STDIN>, употребленная в списковом контексте, создаваемом операцией sort сортировки списка, будет создавать списковый контекст для своего операнда, что приведет к чтению всех вводимых пользователем строк, пока не встретится символ конца файла (Ctrl+Z):
sort(<STDIN>);
ВНИМАНИЕ Осуществляет ли операция перегрузку в зависимости от контекста использования, можно узнать, обратившись к документации, поставляемой с интерпретатором языка.
Большинство перегружаемых операций «требуют» вычисления своих операндов в том контексте, в котором они сами выполняются. Несколько иначе ведет себя операция присваивания, которая создает контекст для правого операнда в зависимости от типа левого операнда. Если последний является скалярной переменной, то правый операнд вычисляется в скалярном контексте, а если левый операнд представлен массивом, то это предписывает вычислять правый операнд в списковом контексте.
Скалярный контекст можно подразделить на числовой, строковый и безразличный. Однако ни одна операция не может определить, вычисляется ли она в одном из перечисленных контекстов, так как «переключение» между этими контекстами осуществляется самим интерпретатором — при необходимости строки преобразуются в числовые значения и наоборот. Операция может только «понять», вычисляется ли она в скалярном или списковом контексте. Иногда вообще безразлично, возвращается ли операцией число или строка. Подобное происходит в операции присваивания. Здесь не важен тип присваиваемого значения — переменная или элемент массива, определяемые в левой части операции присваивания, просто принимают скалярный подтип возвращаемого значения операции правой части. Такой контекст называется безразличным.
Для выполнения некоторых операторов и операций Perl требуется трактовать результаты вычисления выражений как булевы значения «истина» или «ложь». Такое поведение предоставляет булевый контекст — специальный тип скалярного контекста, в котором скалярная величина трактуется как «истина», если только она не равна пустой строке "", строке "0" или числу 0 (целому или вещественному). Перечисленные значения, и только они, могут представлять в программе Perl «ложь». Строки "00", "0.0", "0e0" и т. п. рассматриваются в булевом контексте как «истина». Этот контекст появляется в условных операторах и простых операторах с модификаторами, о которых речь пойдет в главе 5.
Другим специфическим типом скалярного контекста является void-контекст. Он не только не заботится о подтипе возвращаемого значения — скалярный он или числовой, — но ему и не надо никакого возвращаемого значения. Этот контекст появляется при вычислении выражения без побочного эффекта, то есть когда не изменяется никакая переменная программы. Например, следующие выражения вычисляются в void-контексте:
$n; 
"string";
Этот контекст можно обнаружить, если установить ключ -w компилятора perl. Тогда при вычислении предыдущих операторов вы получите предупреждающие сообщения следующего вида:
Useless use of a variable in void context at ex04-01.pl line 2.
Useless use of a constant in void context at ex04-01.pl  line 3.
(Бесполезное использование переменной (константы) в void-контексте 
в строке 2 (3)программы ex04-01.pl)
Если первое из представленных выражений заменить на выражение с побочным эффектом, например $n++;, то первое предупреждение отображаться не будет.

Следующая страница Содержание главы


Реклама