Строковые функции
Сейчас мы рассмотрим строковые функции. С помощью этих функций вы можете определить длину строки, произвести поиск подстроки или поменять местами символы в строке. Ниже приведены строковые функции, имеющиеся в Perl:

chomp (string), chomp (array) использует значение специальной переменной $/ для последнего символа строки string или каждого элемента массива array. Последний символ будет удален только в том случае, если он равен значению переменой $/.

chop (string), chop (array) делает то же самое, что и предыдущая функция, но в качестве результата эта функция возвращает сам удаленный символ.

chr (number) возвращает символ из ASCII-таблицы с кодом number. Например, chr(65) возвратит символ "A".

crypt (string1, string2) шифрует строку string1. Perl не предоставляет механизмов для дешифрования строки.

index (string, substring, position) возвращает позицию первого вхождения строки substring в строке string считая от позиции position. Если параметр position не задан, то сравнение строк ведется от начала строки string.

join (string, array) возвращает строку, в которой все элементы массива array соединены строкой string. Например, join (">>", ("a","b","c")) возвратит строку "a>>b>>c";

lc (string) возвратит строку, где все символы прописные. Например, lc ("ABCD") возвратит "abcd"

lcfirst (string) возвратит строку, в которой только первый символ прописной. Например, lcfirst ("ABCD") возвратит "aBCD"

length (string) возвращает длину строки.

rindex (string, substring, position) то же, что и index (смотрите выше), но возвращает позицию последнего вхождения.

substr (string, offset, length) возвращает часть строки string, как определено параметрами offset (смещение) и length (длина). Если length не указан, возвращается все, что находится на промежутке от offset до конца string. Отрицательные значения offset могут использоваться для сканирования с правого края строки string.

uc (string) то же самое, что и lc (смотрите выше), но все символы заглавные.

ucfirst (string) то же самое, что lcfirst (смотрите выше), но символ заглавный.

В случае, если Perl встречает число там, где ожидает встретить строку, он просто преобразовывает число в строку, освобождая вас от дополнительной работы.

Некоторые функции из приведенных выше используют для своей работы специальную переменную $_, о которой вы узнаете в главе 9 "Файлы" и главе 12 "Использование специальных переменных".

Следующие несколько примеров демонстрируют применение некоторых строковых функций. После того, как вы поймете работу нескольких строковых функций, вы сможете правильно применять и остальные.

Пример: изменение значения строки

Очень часто вам, возможно, понадобится изменять части строк - как правило, где-то в середине строки. Когда перед вами станет такая задача, вы можете воспользоваться функцией substr(). Обычно эта функция используется для получения строки из существующей строки - на основании трех параметров - исходной строки, смещения, которое есть начало новой строки и длины новой строки.

$firstVar = substr("0123BBB789", 4, 3);


Программа напечатает:

firstVar = BBB

Функция возвратит строку, начиная с 5-го символа, и длиной в 3 символа.

Применение данной функции становится гораздо более интересным, когда вы используете ее слева от оператора присваивания:

$firstVar = "0123BBB789";
substr($firstVar, 4, 3) = "AAA";
print("firstVar = $firstVar\n");

Программа напечатает:

FirstVar = 0123AAA789

Пример: поиск строки

Другая интересная задача, которую вы можете решить с помощью строковх функций - это поиск заданной подстроки в строке. Например, у вас есть полное имя файла, включая путь: "C:\\WINDOWS \\TEMP\\WSREWE.DAT", а вам нужно получить из него только имя файла. Вы можете это сделать, найдя последний обратный слеш (символ "\"), а за тем применив функцию substr().

Помните, что в строке для указания символа "\" вы должны использовать двойной символ "\\". Если вы подзабыли материал, обратитесь к главе 2 "Числовые и стринговые литералы".

$pathName = "C:\\WINDOWS\\TEMP\\WSREWE.DAT";
$position = rindex($pathName, "\\") + 1;
$fileName = substr($pathName, $position);
print("$fileName\n");

Программа напечатает:

WSREWE.DAT

Мы не указали здесь третий параметр функции substr() - length, - это потому что нам нужно взять подстроку до конца исходной строки.

Функции для работы с массивами.

Массивы - это большая часть Perl и Perl может вам предложить много функций для работы с ними.

Функции, которые вы можете использовать для работы с массивами:

defined (variable) возвращает true если variable имеет действительное значение, и false если variable пока не было присвоено значение. Это относится не только к массивам, данные любого типа могут быть проверены таким образом. В отношении подобных операций с ключами ассоциативных массивов смотрите функцию exists().

delete (key) удаляет пару "ключ-значение" из данного ассоциативного массива. Если вы удалите подобным образом значение из массива окружения %ENV, то изменится окружение только текущего процесса.

each (assoc_array) возвращает двухэлементый список, содержащий ключ и значение из заданного ассоциативного массива. Если уже был прочитан последний элемент массива, возвращается пустой список.

exists (key) возвращает true, если key является ключем заданного ассоциативного массива. Например, exists ($array("Orange")) возвратит true, если ассоциативный массив %array имеет ключ со значением "Orange".

join (string, array) возвращает строку, в которой все элементы массива array соединены строкой string. Например, join (">>", ("a","b","c")) возвратит строку "a>>b>>c".

keys (assoc_array) возвращает список всех ключей, имеющихся в заданном ассоциативном массиве. Список не составляется в каком-либо определенном порядке.

map (expression, array) вычисляет выражение expression для каждого элемента массива array. Специальная переменная $ присваивается каждому элементу массива array перед вычислением выражения expression.

pack (string, array) создает бинарную структуру, используя string как шаблон, массива array. Подробнее смотрите в главе 8 "Ссылки".

pop (array) возвращает последнее значение массива array, уменьшая его размер на единицу.

push (array1, array2) добавляет содержимое массива array1 к массиву array2, изменяя размер массива array1 должным образом.

reverse (array) когда используется в контексте массива, изменяет порядок следования элементов массива на противоположный. Когда же использется в скалярном контексте, массив преобразуется в строку, а уже строка подвергается реверсивному изменению.

scalar (array) рассматривает массив как скаляр и возвращает количество элементов в массиве.

shift (array) возвращает первое значение массива array, уменьшая его размер на единицу.

sort (array) возвращает список, содержащий элементы массива array, отсортированные в заданном порядке. Подробнее смотрите главу 8 "Ссылки".

splice (array1, offset, length, array2) заменяет элементы массива array1 элементами массива array2. Возвращает список, содержащий все элементы, которые были удалены.

split (pattern, string, limit) разбивает строку string на части, принимая за границу значение параметра pattern. Например, ($a, $b, $c) = split ("::", "1::2::3") присвоит переменным $a, $b, $c значения "1", "2", "3" соответственно. Если же результат используется в скалярном контексте, то функция возвращает количество найденных таким образом элементов.

undef (variable) всегда возвращает неопределенное значение. Кроме того, "разопределяет" переменную variable, которая должна быть скаляром, целым массивом или именем подпрограммы.

unpack (string, array) совершает действия, полностью противоположные деяниям функции pack() - смотрите выше.

unshift (array1, array2) добавляет элементы массива array1 к началу массива array2. Добавляемые элементы сохраняют оригинальный порядок. Возвращает новый размер массива array1.

values (assoc_array) возвращает все значения заданного ассоциативного массива. Возвращаемый список не формируется в каком-либо определенном порядке.

Как и в случае со строковыми функциями, мы рассмотрим в примерах только несколько функций для работы с массивами.

Пример: печать ассоциативного массива.

Как мы уже знаем, функция each() возвращает пару ключ-значение ассоциативного массива. Это называется итерацией элементов массива. То есть, функция начинает работу от начала массива, и заканчивает только в случае достижения конца массива.

%array = ("100", "Green", "200", "Orange");
while (($key, $value) = each(%array)) {
print("$key = $value\n");
}

Программа напечатает:

100 = Green
200 = Orange

По достижении конца массива, функция возвращает false.

Пример: проверка существования элемента массива

Перед тем как присваивать какому-либо элементу массива значение, вы можете проверить - существует ли вообще данный элемент - с помощью функции defined(). Это очень удобно если вы, например, читаете какие-либо значения с диска, и не хотите перезаписывать ими те значения, которые уже содержатся в памяти. Предположим, у вас имеется база данных с адресами клиентов, и вы хотите удостовериться, что в ней нет дубликатов. Вы считываете с диска адреса один за одним, и записываете их в качестве значений в ассоциативный массив, используя имена клиентов как ключи массива. Если имя клиента как ключ массива уже имеется в массиве, то его новый адрес помечается.

Поскольку мы ще не говорили о работе с файлами, то нам потребуется эмулировать работу с диском. И вместо адресов клиентов мы будем использовать номер клиента в паре с его именем. Сначала мы посмотрим, что получится когда в ассоциативном массиве два занчения имеют один ключ.





print("$key, $value\n");
};
sub createPair{
my($key, $value) = @_ ;
$array{$key} = $value;
};

Программа напечатает:

100, George Orwell
200, Grace Kelly

Как вы видите, первая пара массива была перезаписана третьей парой. Таким образом, чтобы избежать ошибок, нам нужно иметь возможность достоверно проверить - нет ли в массиве уже такого ключа, который мы собираемся использовать. Следующая программа показывает, как это делается:

createPair("100", "Kathy Jones");
createPair("200", "Grace Kelly");
createPair("100", "George Orwell");
while (($key, $value) = each %array) {
print("$key, $value\n");
};
sub createPair{
my($key, $value) = @_ ;
while (defined($array{$key})) {
$key++;
}
$array{$key} = $value;
};

Программа напечатает:

100, George Orwell
101, Kathy Jones
200, Grace Kelly

Как вы видите, программа заметила, что ключ "100" уже существует, и новые данные добавила в массив с ключем "101". Если бы, например, ключ "101" уже существовал в массиве, то новые данные таким образом добавились бы с ключем "102".

Встпвляет пространство имен одного модуля в другой. Это не встроенная функция, а всего лищь метод, наследуемый от модуля (параметр МОДУЛЬ), которому необходимо экспортировать свои имена (параметр СПИСОК) в другой модуль.

Import МОДУЛЬ СПИСОК

local

Функция local() используется для объявления и инициализации одной или нескольких переменных:

Local EXPR local ($myvar, , %myhash); local $pi = 3.14159; local ($pi, $exp) = (3.14159, 2.71828);

но, в отличие от функции my() она создает не локальные переменные, а временные значения для глобальных переменных внутри:

  • подпрограммы;
  • заключенного в фигурные скобки блока операторов;
  • выражения, пареданного на выполнение функции eval();
  • файла;

В зависимости от того, в каком месте вызвана для объявления переменных сама функция local(). Если функция local() применяется для описания нескольких переменных, они должны быть заключены в скобки. Если глобальня перемнная, объявленная при помощи этой функции, ранее встречалась до объявления и имела некоторое значение, то это значение сохраняется в скрытом стеке и восстанавливается после выхода соответственно из подпрограммы, блока, функции eval() или файла. Переменная, объявленная при помощи функции local(), или, точнее, ее временное значение, доступна для любой функции, вызванной внутри подпрограммы, блока, функции eval() или файла, в которых сделано объявление. Такую переменную называют динамической, а ее область видимости - динамической областью видимости. В названии отражается тот факт, что область видимости переменной динамически изменяется с каждым вызовом функции, получающей доступ к этой переменной.

Пример:

my

Функция my() используется для объявления одной или нескольких переменных локальными:

и ограничивает их область действия:

  • подпрограммой;
  • заключенным в фигурные скобки блоком операторов;
  • выражением, пареданным на выполнение функции eval();
  • файлом, в зависимости от того, в каком месте вызвана для объявления переменных сама функция my().

Если выражение EXPR содержит список переменных, то он должен быть заключен в скобки:

My ($myvar, @mylist, %myhash);

Одновременно с объявлением переменные могут быть инициализированны:

My $pi = 3.14159; my ($pi, $exp) = (3.14159, 2.71828);

Переменные, объявленные при помощи функции my(), доступны в своей области действия только для подпрограмм, определенных в этой области. Для подпрограмм, определенных за ее пределами, они недоступны. Такие переменные называются лексическими, а саму область видимости - лексической или статической областью видимости.

Пример:

Sub f1{ local ($x) = "aaaa"; my($y) = "bbbb"; print("f1: x = $xn"); print("f1: y = $ynn"); f2(); print("f1: x = $xn"); print("f1: y = $ynn"); } sub f2{ print("f2: x = $xn"); print("f2: y = $ynn"); $x = "cccc"; $y = "dddd"; print("f2: x = $xn"); print("f2: y = $ynn"); } f1;

Результатом выполнения данного примера будет следующий вывод:

F1: x = aaaa f1: y = bbbb f2: x = aaaa f2: y = f2: x = cccc f2: y = dddd f1: x = cccc f1: y = bbbb

Как видно из приведенного результата, функция f2() не имеет доступа к переменной $y, объявленной при помощи функции my() внутри функции f1(), и,напртив, имеет доступ к переменной $x, объявленной внутри f1() при помощи функции local().

package

Определяет отдельное глобальное пространство имен (пакет): все неопределенные динамические идентификаторы (включая те, которые объявлены через local(), но не my()) будут храниться в нем. Для доступа к ним вне пакета следует указывать префикс, представляющий имя пакета с последующими двумя символами двоеточий "::". Область видимости переменных пакета распространяется до конца блока операторов, в котором расположен пакет или до нового объявления пакета. Если опущено имя пакета, то предписывает, чтобы все индентификаторы были определены, включая имена функций.

Package [ИМЯ_ПАКЕТА]

use

Загружает модуль во время компиляции; если модуль не доступен, то компиляция всей программы прекращается.

Use МОДУЛЬ СПИСОК use МОДУЛЬ use МОДУЛЬ ВЕРСИЯ СПИСОК use ВЕРСИЯ

  • Tutorial

В Perl заложено огромное количество возможностей, которые, на первый взгляд, выглядят лишними, а в неопытных руках могут вообще приводить к появлению багов. Доходит до того, что многие программисты, регулярно пишущие на Perl, даже не подозревают о полном функционале этого языка! Причина этого, как нам кажется, заключается в низком качестве и сомнительном содержании литературы для быстрого старта в области программирования на Perl. Это не касается только книг с Ламой, Альпакой и Верблюдом («Learning Perl », «Intermediate Perl » и «Programming Perl ») - мы настоятельно рекомендуем их прочитать.

В этой статье мы хотим подробно рассказать о маленьких хитростях работы с Perl, касающихся необычного использования функций, которые могут пригодится всем, кто интересуется этим языком.

Как работают функции Perl?

В большинстве языков программирования описание функции выглядит примерно так:
function myFunction (a, b) { return a + b; }
А вызывается функция так:
myFunction(1, 2);
На первый взгляд всё просто и понятно. Однако вызов этой функции в следующем виде:
myFunction(1, 2, 3); … в большинстве случаев приведёт к ошибкам, связанным с тем, что в функцию передано неверное количество аргументов.

Функция в Perl может быть записана так:
sub my_sub($$;$) : MyAttribute { my ($param) = @_; }
Где $$;$ - это прототип, а MyAttribute - это атрибут. Прототипы и атрибуты будут рассмотрены далее в статье. А мы пока рассмотрим более простой вариант записи функции:
sub my_sub { return 1; }
Здесь мы написали функцию, которая возвращает единицу.

Но в этой записи не указано, сколько аргументов принимает функция. Именно поэтому ничего не мешает вызвать её вот так:
my_sub("Туземец", "Бусы", "Колбаса", 42);
И всё прекрасно выполняется! Это происходит потому, что в Perl передача параметров в функцию сделана хитро. Perl славится тем, что у него много так называемых «специальных» переменных. В каждой функции доступна специальная переменная @_, которая является массивом входящих параметров.

Поэтому внутри функции мы можем поместить входные параметры в переменные так:
my ($param) = @_;
Это работает и в случае нескольких параметров:
my ($param1, $param2, $param3) = @_;

Очень часто в функциях пишут следующее:
sub my_sub { my $param = shift; ... }
Дело в том, что в Perl многие функции при вызове без аргументов используют переменные по умолчанию. shift же по умолчанию достаёт данные из массива @_. Поэтому записи:
my $param = shift; … и
my $param = shift @_; … совершенно эквивалентны, но первая запись короче и очевидна для Perl-программистов, поэтому используется именно она.

Shift можно использовать и для получения нескольких параметров, в том числе комбинируя в одно списочное присваивание:
my ($one, $two, $three) = (shift, shift, shift);
Другая запись:
my ($one, $two, $three) = @_; … работает точно так же.

А теперь внимание! Грабли, на которые рано или поздно наступает каждый Perl-программист:
sub my_sub { my $var = @_; print $var; }
Если вызвать данную функцию как my_sub(1, 2, 3) в $var мы внезапно получим не 1, а 3. Это происходит потому, что в данном случае контекст переменной определяется как скалярный, а в Perl массив в скалярном контексте возвращает свой размер, а не первый элемент. Чтобы исправить ошибку, достаточно взять $var в скобки, чтобы контекст стал списочным. Вот так:
sub my_sub { my ($var) = @_ }
И теперь, как и ожидалось, при вызове my_sub(1, 2, 3) в $var будет 1.

Кроме того, в Perl параметры передаются по ссылке. Это значит, что мы можем внутри функции модифицировать параметры, которые в неё переданы.

Например:
my $var = 5; my_sub($var); print $var; sub my_sub { # вспоминаем, что доступ к элементам массива выполняется в скалярном контексте # т. е. доступ к нулевому элементу массива @arr будет выглядеть как $arr, то же самое и с # @_. $_++; # $_ - первый элемент массива @_. }
Результат будет 6. Однако в Perl можно сделать в каком-то роде «передачу по значению» вот так:
my $var = 5; my_sub($var); print $var; sub my_sub { my ($param) = @_; $param++; }
А вот теперь результат будет 5.

И последние два нюанса, которые очень важны. Perl автоматически возвращает из функции результат последнего выражения.

Возьмём код из предыдущего примера и немного его модифицируем:
my $var = 5; my $result = my_sub($var); print $result; sub my_sub { my ($param) = @_; ++$param; }
Это будет работать точно так же, как если бы в последней строке функции был явный возврат значения:
return ++$param;
Функция вернёт 6.

И ещё одна особенность: если в теле функции вызывается другая функция с использованием амперсанда и без скобок, то внутренняя функция получает на вход параметры той функции, в теле которой она вызывается. Т. е. массив @_ будет автоматически передан из внешней функции во внутреннюю. Это может привести к неочевидным багам.
use strict; use Data::Dumper; my_sub(1, 2, 3); sub my_sub { &inner; } sub inner { print Dumper \@_; }
Результат:
$VAR1 = [
1,
2,
3
];

Однако, если явно указать (с помощью пустых скобок), что функция вызывается без параметров, то всё в порядке:
sub my_sub { &inner(); }
И вывод будет выглядеть вот так:
$VAR1 = ;

Впрочем, вызовы функций с использованием амперсанда используются очень редко и в коде почти не встречаются.

Анонимные функции

Анонимные функции объявляются в месте использования и не получают уникального идентификатора для доступа к ним. При создании они либо вызываются напрямую, либо ссылка на функцию присваивается переменной, с помощью которой затем можно косвенно вызывать эту функцию.

Элементарное объявление анонимной функции в Perl:
my $subroutine = sub { my $msg = shift; printf "I am called with message: %s\n", $msg; return 42; }; # $subroutine теперь ссылается на анонимную функцию $subroutine->("Oh, my message!");
Анонимные функции можно и нужно использовать как для создания блоков кода, так и для замыканий, о которых речь дальше.

Замыкания

Замыкание - это особый вид функции, в теле которой используются переменные, объявленные вне тела этой функции.

В записи это выглядит как, например, функция, находящаяся целиком в теле другой функции.
# возвращает ссылку на анонимную функцию sub adder($) { my $x = shift; # в котором x - свободная переменная, return sub ($) { my $y = shift; # а y - связанная переменная return $x + $y; }; } $add1 = adder(1); # делаем процедуру для прибавления 1 print $add1->(10); # печатает 11 $sub1 = adder(-1); # делаем процедуру для вычитания 1 print $sub1->(10); # печатает 9
Замыкания использовать полезно, например, когда необходимо получить функцию с уже готовыми параметрами, которые будут в ней сохранены. Или же для генерации функции-парсера, колбеков.

Бесскобочные функции

На наш взгляд, это самый подходящий перевод термина parenthesis-less.

Например, print часто пишется и вызывается без скобок. Возникает вопрос, а можем ли мы тоже создавать такие функции?

Безусловно. Для этого у Perl есть даже специальная прагма - subs. Предположим, нам нужна функция, проверяющая значение переменной на истинность.
use strict; use subs qw/checkflag/; my $flag = 1; print "OK" if checkflag; sub checkflag { return $flag; }
Эта программа напечатает OK.

Но это не единственный способ. Perl хорошо продуман, поэтому, если мы реструктуризируем нашу программу и приведём её к такому виду:
use strict; my $flag = 1; sub checkflag { return $flag; } print "OK" if checkflag; …то результат будет тот же.

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

  • используя прагму subs;
  • написав функцию ПЕРЕД её вызовом;
  • используя прототипы функций.
Обратимся к последнему варианту.

Прототипы функций


Зачастую разное понимание цели этого механизма приводит к холиварам с адептами других языков, утверждающих, что «у перла плохие прототипы». Так вот, прототипы в Perl не для жёсткого ограничения типов параметров, передаваемых функциям. Это подсказка для языка: как разбирать то, что передаётся в функцию.

Есть, к примеру, абстрактная функция, которая называется my_sub:
sub my_sub { print join ", ", @_; }
Мы её вызываем следующим образом:
my_sub(1, 2, 3, 4, 5);
Функция напечатает следующее:
1, 2, 3, 4, 5,

Получается, что в любую функцию Perl можно передать любое количество аргументов. И пусть сама функция разбирается, что мы от неё хотели.

Предполагается, что должен быть механизм контроля переданных в функцию аргументов. Эту роль и выполняют прототипы.

Функция Perl с прототипами будет выглядеть так:
sub my_sub($$;$) { my ($v1, $v2, $v3) = @_; $v3 ||= "empty"; printf("v1: %s, v2: %s, v3: %s\n", $v1, $v2, $v3); }
Прототипы функций записываются после имени функции в круглых скобках. Прототип $$;$ означает, что в качестве параметров необходимо присутствие двух скаляров и третьего по желанию, «;» отделяет обязательные параметры от возможных.

Если же мы попробуем вызвать её вот так:
my_sub(); …то получим ошибку вида:
Not enough arguments for main::my_sub at pragmaticperl.pl line 7, near "()"
Execution of pragmaticperl.pl aborted due to compilation errors.

А если так:
&my_sub(); …то проверка прототипов не будет происходить.

Резюмируем. Прототипы будут работать в следующих случаях:

  • Если функция вызывается без знака амперсанда (&). Perlcritic (средство статического анализа Perl кода), кстати говоря, ругается на запись вызова функции через амперсанд, то есть такой вариант вызова не рекомендуется.
  • Если функция написана перед вызовом. Если мы сначала вызовем функцию, а потом её напишем, при включённых warnings получим следующее предупреждение:
    main::my_sub() called too early to check prototype at pragmaticperl.pl line 4
Ниже пример правильной программы с прототипами Perl:
use strict; use warnings; use subs qw/my_sub/; sub my_sub($$;$) { my ($v1, $v2, $v3) = @_; $v3 ||= "empty"; printf("v1: %s, v2: %s, v3: %s\n", $v1, $v2, $v3); } my_sub();
В Perl существует возможность узнать, какой у функции прототип. Например:
perl -e "print prototype("CORE::read")"
Выдаст:
*\$$;$

Оверрайд методов

Оверрайд - часто довольно полезная штука. Например, у нас есть модуль, который писал некий N. И всё в нём хорошо, а вот один метод, допустим, call_me, должен всегда возвращать 1, иначе беда, а метод из базовой поставки модуля возвращает всегда 0. Код модуля трогать нельзя.

Пусть программа выглядит следующим образом:
use strict; use Data::Dumper; my $obj = Top->new(); if ($obj->call_me()) { print "Purrrrfect\n"; } else { print "OKAY:(\n"; } package Top; use strict; sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } sub call_me { print "call_me from TOP called!\n"; return 0; } 1;
Она выведет:
call_me from TOP called!
OKAY:(

И снова у нас есть решение.

Допишем перед вызовом $obj->call_me() следующую вещь:
*Top::call_me = sub { print "Overrided subroutine called!\n"; return 1; };
А ещё лучше, для временного оверрайда используем ключевое слово local:
local *Top::call_me = sub { print "Overrided subroutine called!\n"; return 1; };
Это заменит функцию call_me пакета Top в лексической области видимости (в текущем блоке).
Теперь наш вывод будет выглядеть так:
Overrided subroutine called!
Purrrrfect

Код модуля не меняли, функция теперь делает то, что нам надо.

На заметку: если приходится часто использовать данный приём в работе - налицо архитектурный косяк. Хороший пример использования - добавление вывода отладочной информации в функции.

Wantarray

В Perl есть такая полезная штука, которая позволяет определить, в каком контексте
вызывается функция. Например, мы хотим, чтобы функция вела себя следующим образом:
когда надо возвращала массив, а иначе - ссылку на массив. Это можно реализовать, и
к тому же очень просто, с помощью wantarray. Напишем простую программу для демонстрации:
#!/usr/bin/env perl use strict; use Data::Dumper; my @result = my_cool_sub(); print Dumper @result; my $result = my_cool_sub(); print Dumper $result; sub my_cool_sub { my @array = (1, 2, 3); if (wantarray) { print "ARRAY!\n"; return @array; } else { print "REFERENCE!\n"; return \@array; } }
Что выведет:
ARRAY!
$VAR1 = 1;
$VAR2 = 2;
$VAR3 = 3;
REFERENCE!
$VAR1 = [
1,
2,
3
];

Также хотелось бы напомнить про интересную особенность Perl. %hash = @аrray; В этом случае Perl построит хэш вида ($array => $array, $array => $array);

Посему, если применять my %hash = my_cool_sub(), будет использована ветка логики wantarray. И именно по этой причине wanthash нет.

AUTOLOAD

В Perl одна из лучших систем управления модулями. Мало того что программист может контролировать все стадии исполнения модуля, так ещё существуют интересные особенности, которые делают жизнь проще. Например, AUTOLOAD.

Суть AUTOLOAD в том, что когда вызываемой функции в модуле не существует, Perl ищет функцию AUTOLOAD в этом модуле, и только затем, если не находит, выбрасывает исключение о вызове несуществующей функции. Это значит, что мы можем описать обработчик ситуаций, когда вызывается несуществующая функция.

Например:
#!/usr/bin/env perl use strict; Autoload::Demo::hello(); Autoload::Demo::asdfgh(1, 2, 3); Autoload::Demo::qwerty(); package Autoload::Demo; use strict; use warnings; our $AUTOLOAD; sub AUTOLOAD { print $AUTOLOAD, " called with params: ", join (", ", @_), "\n"; } sub hello { print "Hello!\n"; } 1;
Очевидно, что функций qwerty и asdfgh не существует в пакете Autoload::Demo. В функции AUTOLOAD специальная глобальная переменная $AUTOLOAD устанавливается равной функции, которая не была найдена.

Вывод этой программы:
Hello!
Autoload::Demo::asdfgh called with params: 1, 2, 3
Autoload::Demo::qwerty called with params:

Генерация функций на лету

Допустим, нам нужно написать множество функций, выполняющих примерно одинаковые действия. Например, набор аксессоров у объекта. Написание подобного кода вряд ли кому-то доставит удовольствие:
sub getName { my $self = shift; return $self->{name}; } sub getAge { my $self = shift; return $self->{age}; } sub getOther { my $self = shift; return $self->{other}; }
Это Perl. «Лень, нетерпение, надменность» (Л. Уолл).

Функции можно генерировать. В Perl есть такая штука как тип данных typeglob. Наиболее точный перевод названия - таблица имён. Typeglob имеет свой сигил - «*».

Для начала посмотрим код:
#!/usr/bin/env perl use strict; use warnings; package MyCoolPackage; sub getName { my $self = shift; return $self->{name}; } sub getAge { my $self = shift; return $self->{age}; } sub getOther { my $self = shift; return $self->{other}; } foreach (keys %{*MyCoolPackage::}) { print $_." => ".$MyCoolPackage::{$_}."\n"; }
Вывод:
getOther => *MyCoolPackage::getOther
getName => *MyCoolPackage::getName
getAge => *MyCoolPackage::getAge

В принципе, глоб - это хэш с именем пакета, в котором он определен. Он содержит в качестве ключей элементы модуля + глобальные переменные (our). Логично предположить, что если мы добавим в хэш свой ключ, то этот ключ станет доступен как обычная сущность. Воспользуемся генерацией функций для генерации данных геттеров.

И вот что у нас получилось:
#!/usr/bin/env perl use strict; use warnings; $\ = "\n"; my $person = Person->new(name => "justnoxx", age => "25", other => "perl programmer",); print "Name: ", $person->get_name(); print "Age: ", $person->get_age(); print "Other: ", $person->get_other(); package Person; use strict; use warnings; sub new { my ($class, %params) = @_; my $self = {}; no strict "refs"; for my $key (keys %params) { # __PACKAGE__ равен текущему модулю, это встроенная # волшебная строка # следующая строка превращается в, например: # Person::get_name = sub {...}; *{__PACKAGE__ . "::" . "get_$key"} = sub { my $self = shift; return $self->{$key}; }; $self->{$key} = $params{$key}; } bless $self, $class; return $self; } 1;
Эта программа напечатает:
Name: justnoxx
Age: 25
Other: perl programmer

Атрибуты функций

В Python есть такое понятие как декоратор. Это такая штуковина, которая позволяет «добавить объекту дополнительное поведение».

Да, в Perl декораторов нет, зато есть атрибуты функций. Если мы откроем perldoc perlsub и посмотрим на описание функции, то увидим любопытную запись:
sub NAME(PROTO) : ATTRS BLOCK
Таким образом, функция с атрибутами может выглядеть так:
sub my_sub($$;$) : MyAttr { print "Hello, I am sub with attributes and prototypes!"; }
Работа с атрибутами в Perl - дело нетривиальное, потому уже довольно давно в стандартную поставку Perl входит модуль Attribute::Handlers.

Дело в том, что атрибуты из коробки имеют довольно много ограничений и нюансов работы, так что, если кому-то интересно, можно обсудить в комментариях.

Допустим, у нас есть функция, которая может быть вызвана только в том случае, если пользователь авторизован. За то, что пользователь авторизован отвечает переменная $auth, которая равна 1, если пользователь авторизован, и 0, если нет. Мы можем сделать следующим образом:
my $auth = 1; sub my_sub { if ($auth) { print "Okay!\n"; return 1; } print "YOU SHALL NOT PASS!!!1111"; return 0; }
И это приемлемое решение.

Но может возникнуть такая ситуация, что функций будет становиться больше и больше. А в каждой делать проверку будет всё накладнее. Проблему можно решить с помощью атрибутов.
use strict; use warnings; use Attribute::Handlers; use Data::Dumper; my_sub(); sub new { return bless {}, shift; } sub isAuth: ATTR(CODE) { my ($package, $symbol, $referent, $attr, $data, $phase, $filename, $linenum) = @_; no warnings "redefine"; unless (is_auth()) { *{$symbol} = sub { require Carp; Carp::croak "YOU SHALL NOT PASS\n"; }; } } sub my_sub: isAuth { print "I am called only for auth users!\n"; } sub is_auth { return 0; }
В данном примере вывод программы будет выглядеть так:
YOU SHALL NOT PASS at myattr.pl line 18. main::__ANON__() called at myattr.pl line 6

А если мы заменим return 0 на return 1 в is_auth, то:
I am called only for auth users!

Не зря атрибуты представлены в конце статьи. Для того чтобы написать этот пример, мы воспользовались:

  • анонимными функциями
  • оверрайдом функций
  • специальной формой оператора goto
Несмотря на довольно громоздкий синтаксис, атрибуты успешно и активно применяются, например, в веб-фреймворке Catalyst. Однако, не стоит забывать, что атрибуты, всё-таки, являются экспериментальной фичей Perl, а потому их синтаксис может меняться в следующих версиях языка.

Статья написана в соавторстве и по техническому материалу от Дмитрия Шаматрина (@justnoxx) и при содействии программистов REG.RU: Тимура Нозадзе (@TimurN), Виктора Ефимова (@vsespb), Полины Шубиной (@imagostorm), Andrew Nugged (@nugged)

: atan2 число1 , число2 Аргументы : число1 , число2 — числовые выражения Результат : числовое значение

Функция atan2 возвращает арктангенс частного от деления числа1 на число2 . Результат находится в диапазоне от -π до +π и соответствует величине угла в радианах между осью абсцисс и вектором до точки с координатами (число2 , число1 ). Примеры:

$x = atan2 -0, -1; # x равно -3.14159265358979 $x = atan2 -1, 0; # x равно -1.5707963267949 $x = atan2 0, 1; # x равно 0 $x = atan2 1, 1; # x равно 0.785398163397448 $x = atan2 1, 0; # x равно 1.5707963267949 $x = atan2 0, -1; # x равно 3.14159265358979

Функция cos

Синтаксис : cos число Аргументы : число — числовое выражение Результат : числовое значение

Функция cos возвращает косинус числа . Если аргумент опущен, то число

$pi = atan2 0, -1; $x = cos 0; # x равно 1 $x = cos $pi/2; # x равно 6e-17 (почти 0) $x = cos $pi; # x равно -1

Функция exp

Синтаксис : exp число Аргументы : число — числовое выражение Результат : числовое значение

Функция exp возвращает экспоненту числа . Если аргумент опущен, то число принимается равным значению переменной $_ . Если число больше 709.78, то возвращается 1.#INF. Пример:

Print exp 1; # 2.71828182845905

Функция int

Синтаксис : int число Аргументы : число — числовое выражение Результат : числовое значение

Функция int возвращает целую часть числа . Если аргумент опущен, то число

Print int 1.5; # 1 print int -1.5; # -1

Функция log

Синтаксис : log число Аргументы : число — числовое выражение Результат : числовое значение

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

Print log 2.71828182845905; # 1

Функция rand

Синтаксис : rand число Аргументы : число — числовое выражение Результат : числовое значение

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

Функция sin

Синтаксис : sin число Аргументы : число — числовое выражение Результат : числовое значение

Функция sin возвращает синус числа . Если аргумент опущен, то число принимается равным значению переменной $_ . Примеры:

$pi = atan2 0, -1; $x = sin 0; # x равно 0 $x = sin $pi/2; # x равно 1 $x = sin -$pi/2; # x равно -1

Функция sqrt

Синтаксис : sqrt число Аргументы : число — числовое выражение Результат : числовое значение

Функция sqrt возвращает квадратный корень из числа . Если аргумент опущен, то число принимается равным значению переменной $_ . Если аргумент меньше или равен нулю, то возникает фатальная ошибка исполнения. Пример:

Print sqrt 2; # 1.4142135623731

Функция srand

Синтаксис : srand число Аргументы : число — числовое выражение

Функция srand инициализирует генератор случайных чисел . Если ее аргумент опущен, то число генерируется исполняющей системой. Начиная с PERL 5.004, явный вызов этой функции не нужен, т. к. теперь она автоматически вызывается функцией rand() при первом обращении к ней.

6.9.2. Строковые функции

Функция chomp

Синтаксис : chomp строка chomp список Аргументы : строка — строковое выражение список Результат : числовое значение

Функция chomp удаляет из строки концевую подстроку, соответствующую текущему разделителю записей, т. е. содержимому переменной $/ . Если аргументом является список , то эта функция применяется к каждому элементу списка. Если аргумент опущен, то строка принимается равной значению переменной $_ . Результатом функции является общее количество удаленных символов.

Ее основным применением является удаление концевых символов перевода строки при построчном чтении текстового файла, например:

While (<>) { chomp; # удаляем \n в конце считанной строки $_ . . . }

Если $\ равно undef или содержит ссылку на число (для записей фиксированной длины), то эта функция ничего не удаляет.

Функция chop

Синтаксис : chop строка chop список Аргументы : строка — строковое выражение список — список строковых выражений Результат : строковое значение

Функция chop удаляет из строки ее последний символ и возвращает его. Если аргументом является список , то эта функция применяется к каждому элементу списка и возвращает последний из удаленных символов. Если аргумент опущен, то строка

$_ = "abcde"; chop; print; # выводит "abcd"

Функция crypt

Синтаксис : crypt строка , код Аргументы : строка , код — строковые выражения Результат : строковое значение

Функция crypt кодирует исходную строку с помощью строки код и возвращает результат. Код должен состоять из двух символов, лежащих в диапазоне [./0-9A-Za-z] . Парной функции декодировки в PERL"е нет, поэтому практического применения эта функция не имеет.

Функция index

Синтаксис : index строка , подстрока , позиция ? Аргументы : строка , подстрока — строковые выражения позиция — числовое выражение Результат : числовое значение

Функция index ищет в строке заданную подстроку , начиная с заданной позиции или с начала строки, если позиция

$str = "Queen Mary"; print index($str, "Mary"); # 6 print index($str, "mary"); # -1

Функция lc

Синтаксис : lc строка Аргументы : строка — строковое выражение Результат : строковое значение

Функция lc преобразует все символы строки в строчные буквы. Если аргумент опущен, то строка

Print lc "ABCDE"; # abcde

Функция lcfirst

Синтаксис : lcfirst строка Аргументы : строка — строковое выражение Результат : строковое значение

Функция lcfirst преобразует первый символ строки в строчную букву. Если аргумент опущен, то строка принимается равной значению переменной $_ . Если использована директива use locale , то преобразование производится с учетом текущей национальной настройки. Пример:

Print lcfirst "ABCDE"; # aBCDE

Функция length

Синтаксис : length строка Аргументы : строка — строковое выражение Результат : числовое значение

Функция length возвращает количество символов в строке . Если аргумент опущен, то строка принимается равной значению переменной $_ . Пример:

Print length "ABCDE"; # 5

Функция rindex

Синтаксис : rindex строка , подстрока , позиция ? Аргументы : строка , подстрока — строковые выражения позиция — числовое выражение Результат : числовое значение

Функция rindex ищет в строке заданную подстроку справа налево, начиная с заданной позиции или с конца строки, если позиция опущена. Она возвращает позицию найденной подстроки в исходной строке или -1, если подстрока не найдена. Пример:

Print rindex("abcabc", "abc"); # 3

Функция substr

Синтаксис : substr строка , смещение , длина ?, замена ? Аргументы : строка , замена — строковые выражения смещение , длина — числовые выражения Результат : строковое значение

Функция substr возвращает подстроку строки заданной длины , начиная с заданного смещения . Если смещение отрицательно, то оно отсчитывается от конца строки. Если длина опущена, то извлекаются символы до конца строки; если она отрицательна, то она складывается с длиной строки. Пример:

Print substr("abcdef", 1, -2); # bcd

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

$str = "abcdef"; substr($str, 1, -2,"xxx"); print $str; # axxxef

Этот пример можно записать и так:

$str = "abcdef"; substr($str, 1, -2) = "xxx"; print $str; # axxxef

Функция uc

Синтаксис : uc строка Аргументы : строка — строковое выражение Результат : строковое значение

Функция uc преобразует все символы строки в прописные буквы. Если аргумент опущен, то строка принимается равной значению переменной $_ . Если использована директива use locale , то преобразование производится с учетом текущей национальной настройки. Пример:

Print uc "abcde"; # ABCDE

Функция ucfirst

Синтаксис : ucfirst строка Аргументы : строка — строковое выражение Результат : строковое значение

Функция ucfirst преобразует первый символ строки в прописную букву. Если аргумент опущен, то строка принимается равной значению переменной $_ . Если использована директива use locale , то преобразование производится с учетом текущей национальной настройки. Пример:

Print ucfirst "abcde"; # Abcde

6.9.3. Прочие скалярные функции

Функция chr

Синтаксис : chr код Аргументы : код — числовое выражение Результат : строковое значение

Функция chr возвращает символ, имеющий заданный числовой код . Если аргумент опущен, то код принимается равным значению переменной $_ . Пример:

Print chr 65; // A

Функция hex

Синтаксис : hex строка Аргументы : строка — строковое выражение Результат : числовое значение

Функция hex преобразует строку в шестнадцатеричное число. Если аргумент опущен, то строка принимается равной значению переменной $_ . Например, все приведенные ниже операторы выведут на экран число 165:

Print hex "0xaf"; print hex "xaf"; print hex "0af"; print hex "af";

Функция oct

Синтаксис : oct строка Аргументы : строка — строковое выражение Результат : числовое значение

Функция oct преобразует строку в число. Если строка начинается с "0x", то она интерпретируется как шестнадцатеричное число; если она начинается с "0b", то интерпретируется как двоичное число; в остальных случаях она интерпретируется как восьмеричное число. Если аргумент опущен, то строка принимается равной значению переменной $_ . Примеры:

Print oct "0xaf"; # 165 print oct "0b101"; # 5 print oct "0100"; # 64 print oct "100"; #64

Функция ord

Синтаксис : ord строка Аргументы : строка — строковое выражение Результат : числовое значение

Функция ord возвращает числовой код первого символа строки . Если аргумент опущен, то строка принимается равной значению переменной $_ . Пример:

Print ord "ABC"; # 65

Функция pack

Синтаксис : pack шаблон , список Аргументы : шаблон — строковое выражение список — список скалярных выражений Результат : строковое значение

Функция pack упаковывает заданный список значений в строку и возвращает его в качестве результата. Правила упаковки задаются строкой шаблон , которая состоит из символов, указывающих правила преобразования для элементов списка. Шаблон может содержать следующие символы:

Символ Результат
a Произвольная строка, в конце добавить нулевой байт.
A Строка ASCII, в конце добавить пробел.
Z Строка ASCII, в конце добавить нулевой байт.
b Битовая строка, биты в байте упаковываются с младшего бита.
B Битовая строка, биты в байте упаковываются со старшего бита.
h Шестнадцатеричная строка, младшая тетрада идет первой.
H Шестнадцатеричная строка, старшая тетрада идет первой.
c Однобайтовое целое со знаком.
C Однобайтовое целое без знака.
s Двухбайтовое целое со знаком.
S Двухбайтовое целое без знака.
i Целое со знаком (число байтов зависит от архитектуры).
I Целое без знака (число байтов зависит от архитектуры).
l Четырехбайтовое целое со знаком.
L Четырехбайтовое целое без знака.
n Двухбайтовое целое без знака, старший байт идет первым.
N Четырехбайтовое целое без знака, старший байт идет первым.
v Двухбайтовое целое без знака, младший байт идет первым.
V Четырехбайтовое целое без знака, младший байт идет первым.
q Восьмибайтовое целое со знаком.
Q Восьмибайтовое целое без знака.
f Плавающее число обычной точности, формат зависит от архитектуры.
d Плавающее число двойной точности, формат зависит от архитектуры.
p Указатель на строку с завершающим нулевым байтом.
P Указатель на структуру фиксированной длины.
u Строка в кодировке uuencode.
U Строка в кодировке UTF-8.
w Сжатое целое формата BER.
x Нулевой байт.
X Дублировать байт.
@ Заполнение нулями до указанной позиции.

Шаблоны подчиняются следующим правилам:

  • За буквой может следовать число, задающее счетчик повторений. Для всех типов, кроме a, A, Z, b, B, h, H, P , извлекается соответствующее количество элементов списка . Если счетчик задан символом * , это означает упаковку всех оставшихся элементов списка (за исключением @, x, X , где этот символ эквивалентен 0, и u , где он эквивалентен 1). Z* означает добавление дополнительного нулевого байта в конец строки. Счетчик повторений для u интерпретируется как максимальное число байтов, которое должно кодироваться в одной строке вывода; при этом 0 и 1 заменяются на 45.
  • Типы a, A, Z всегда извлекают из списка одно значение. Счетчик повторений для них означает длину упакованной строки. Если строка длиннее счетчика, то она усекается; если короче, то дополняется нулями (a, Z) или пробелами (A). При упаковке a и Z эквивалентны; при распаковке A удаляет из строки концевые пробелы и нулевые байты, Z удаляет все после первого нулевого байта, a ничего не удаляет.
  • Типы b и B преобразуют каждый из входных байтов в один бит результата. Результирующий бит равен 0 или 1 в зависимости от значения младшего бита исходного байта. Счетчик повторений задает количество упаковываемых байтов. При этом b упаковывает получаемые биты в байт результата, начиная с младшего его бита, а B — со старшего. Если длина исходной строки не делится на 8, то результат дополняется нулевыми битами. При распаковке эти лишние биты игнорируются. Если входная строка длиннее счетчика, то она усекается. * в качестве счетчика повторений означает использование всех байтов входного поля. При распаковке биты преобразуются в байты "0" и "1".
  • Для типов h и H счетчик повторений означает количество упаковываемых шестнадцатеричных цифр (тетрад). Каждый из входных байтов преобразуется в одну тетраду результата. При этом байты "0"… "9", "a"…"f", "A"…"F" заменяются на соответствующие шестнадцатеричные цифры, а остальные байты на свою младшую тетраду. Тип h упаковывает получаемые тетрады в байт результата, начиная с младшего его тетрады, а H — со старшей. Если длина исходной строки нечетна, то результат дополняется нулевой тетрадой. При распаковке лишняя тетрада игнорируются. Если входная строка длиннее счетчика, то она усекается. * в качестве счетчика повторений означает использование всех байтов входного поля. При распаковке тетрады преобразуются в строку шестнадцатеричных цифр.
  • Тип p упаковывает указатель на строку, оканчивающуюся нулевым байтом, а P — указатель на структуру фиксированной длины, заданной счетчиком повторений. Если значение соответствующего указателя равно undef , то упаковывается нуль.
  • Символ / вместо счетчика повторений позволяет упаковать перед строкой ее длину. Например, шаблон "n/a*" означает, что результат будет состоять из двухбайтового числа, содержащего длину исходной строки, и самой строки.
  • При упаковке не производится никакого выравнивания получаемых значений.
  • Шаблон может содержать комментарий, который начинается с символа # и продолжается до конца строки.
  • Если шаблон требует больше аргументов, чем содержится в списке , то список дополняется пустыми строками "" . Если шаблон требует меньше аргументов, чем содержится в списке , то лишние аргументы игнорируются.

$foo = pack("CCCC",65,66,67,68); # $foo = "ABCD" $foo = pack("C4",65,66,67,68); # $foo = "ABCD" $foo = pack("aaaa","abc","x","y","z"); # $foo = "axyz" $foo = pack("a14","abcdefg"); # "abcdefg\0\0\0\0\0\0\0" $foo = pack("s2",1,2); # $foo = "\1\0\2\0" в IBM PC, "\0\1\0\2" в Mac

Функция unpack

Синтаксис : unpack шаблон , строка Аргументы : шаблон , строка — строковые выражения Результат : массив значений

Функция pack распаковывает строку , упакованную функцией . Она возвращает массив полученных в результате значений (в скалярном контексте возвращает первое полученное значение). Правила распаковки задаются строкой шаблон , строение которой то же, что и для . Дополнительно шаблон может содержать перед буквой, задающей тип распаковки, префикс %n , который указывает, что мы хотим получить не результат распаковки, а его n -битовую контрольную сумму. Остальные подробности см. в описании функции . Следующий пример демонстрирует эффективный способ подсчета количества единичных битов в переменной $mask:

$setbits = unpack("%32b*", $mask);

Функция vec

Синтаксис : vec выражение , смещение , ширина Аргументы : выражение — строковое выражение смещение , ширина — числовые выражения Результат : числовое значение

Функция vec рассматривает строку выражение как массив, состоящий из элементов заданной ширины в битах. Она извлекает элемент с заданным смещением и возвращает его. Ширина должна степенью числа 2 в диапазоне от 1 до 32 (или 64 на 64-битовых платформах), смещение трактуется как целое число без знака. Пример:

$x = "\x10\x32\x54"; # $x = (0, 1, 2, 3, 4, 5) как вектор 4-битовых чисел print vec($x, 2, 4); # поэтому будет выведено число 2

Функция vec может использоваться в левой части оператора присваивания для формирования массива битовых групп в строке. Например, мы могли бы сформировать приведенную выше строку $x так:

Функция quotemeta добавляет в строку аргумента символ "\" перед каждым символом, не являющимся латинской буквой или цифрой, и возвращает новую строку в качестве результата. Если аргумент опущен, то он принимается равным значению переменной $_ . Это внутренняя функция, которая реализует метасимвол \Q . Пример:

Print quotemeta "abc123абв"; # "abc123\а\б\в"

Функция split

Синтаксис : split образец , строка , предел Аргументы : образец — регулярное выражение строка — строковое выражение предел — числовое выражение Результат : список строк

Функция split расщепляет исходную строку на подстроки и возвращает список этих подстрок. В скалярном контексте она заносит список подстрок в массив @_ и возвращает его длину. Если строка опущена, то она принимается равной значению переменной $_ . Разбиение на подстроки происходит в позициях сопоставления с заданным образцом ; если он опущен, то разбиение производится по символу пробела, при этом начальные пробелы в каждой подстроке удаляются. Если образец содержит круглые скобки, то подстроки, сопоставляемые с выражением в скобках, включаются в результирующий список как отдельные элементы.

Если предел задан и положителен, то он задает максимально допустимое количество извлекаемых подстрок. Если он опущен или равен нулю, то конечные пустые подстроки не включаются в результирующий список. Если же он отрицательный, то возвращаются все извлеченные подстроки. Примеры:

@_ = split(/,/, "a,b,c,d,"); # @_ = ("a", "b", "c", "d") @_ = split(/,/, "a,b,c,d,", 3); # @_ = ("a", "b", "c,d,") @_ = split(/,/, "a,b,c,d,", -3); # @_ = ("a", "b", "c", "d", "") @_ = split(/(,)/, "a,b,c,d,"); # @_ = ("a", ",", "b", ",", "c", ",", "d", ",")

Функция study

Синтаксис : study строка Аргументы : строка — строковое выражение Результат : нет

Функция study компилирует строку (или значение переменной $_ , если она опущена) во внутреннее представление. Если строку предполагается многократно сопоставлять с образцом, то ее компиляция может сэкономить время при последующих операциях сопоставления. В каждый момент времени только одна строка может быть скомпилирована; применение функции study к другой строке отменяет компиляцию текущей строки. Пример:

While (<>) { study; print "Мое\n" if /\bменя\b/; print "Твое\n" if /\bтебя\b/; ... }

Проблема

Требуется создать ссылку для вызова подпрограммы. Такая задача возникает при создании обработчиков сигналов, косвенно-вызываемых функций Tk и указателей на хэши функций.

Решение

Получение ссылки на функцию: $cref = \&func; $cref = sub {...}; Вызов функции по ссылке: @returned = $cref->(@arguments); @returned = &$cref (@arguments);

Комментарий

Чтобы получить ссылку на функцию, достаточно снабдить ее имя префиксом \&. Кроме того, формулировка sub {} позволяет создавать анонимные функции. Ссылка на анонимную функцию может быть сохранена так же, как и любая другая. В Perl 5.004 появилась постфиксная запись для разыменования ссылок на функции. Чтобы вызвать функцию по ссылке, раньше приходилось писать &$funcname (@ARGS), где $funcname - имя функции. Возможность сохранить имя функции в переменной осталась и сейчас: $funcname = "thefunc"; &$funcname(); однако подобное решение нежелательно по нескольким причинам. Во-первых, в нем используются символические, а не настоящие (жесткие) ссылки, поэтому при действующей директиве use strict "refs" оно отпадает. Символические ссылки обычно не рекомендуются, поскольку они не могут обращаться к лексическим, а только к глобальным переменным, и для них не ведется подсчет ссылок. Во-вторых, оно не содержит данных о пакете, поэтому выполнение фрагмента в другом пакете может привести к вызову неверной функции. Наконец, если функция была в какой-то момент переопределена (хотя это происходит нечасто), символическая ссылка будет обращаться к текущему определению функции, а жесткая ссылка сохранит старое определение. Вместо того чтобы сохранять имя функции в переменной, создайте ссылку на нее с помощью оператора \. Именно так следует сохранять функцию в переменной или передавать ее другой функции. Ссылки на именованные функции можно комбинировать со ссылками на анонимные функции: %commands = ("happy" => \&joy, "sad" => \&sullen, "done" => sub { die "See ya!" }, "mad" => \&angry,); print "How are you?"; chomp ($string = ); if ($commands{$string}) { $commands{$string}->(); } else { print "No such command: $string\n"; } Если вы создаете анонимную функцию, которая ссылается на лексическую (mу) переменную из вмещающей области действия, схема подсчета ссылок гарантирует, что память лексической переменной не будет освобождена при наличии ссылок на нее: sub counter_maker { my $start = 0; return sub { # Замыкание return $start++; # Лексическая переменная }; # из вмещающей области действия } $counter = counter_maker(); for ($i =0; $i Даже несмотря на то что функция counter_maker завершилась, а переменная $start вышла из области действия, Perl не освобождает ее, поскольку анонимная подпрограмма (на которую ссылается $counter) все еще содержит ссылку на $start. Если повторно вызвать counter_maker, функция вернет ссылку на другую анонимную подпрограмму, использующую другое значение $start: $counter1 = counter_maker(); $counter2 = counter_maker(); for ($i = 0; $i 0 1 2 3 4 5 0 Замыкания часто используются в косвенно-вызываемых функциях (callbacks). В графических интерфейсах и вообще в программировании, основанном на событиях, определенные фрагменты кода связываются с событиями нажатий клавиш, щелчков мышью, отображения окон и т. д. Этот код вызывается много позже, возможно, из совсем другой области действия. Переменные, используемые в замыкании, должны быть доступными к моменту вызова. Для нормальной работы они должны быть лексическими, а не глобальными. Замыкания также используются в генераторах функций, то есть в функциях, которые создают и возвращают другие функции. Функция counter_maker является генератором. Приведем еще один простой пример: sub timestamp { my $start_time = time (); return sub { return time() - $start_time }; } $early = timestamp(); sleep 20; $later = timestamp(); sleep 10; printf "It"s been %d seconds since early.\n", $early->(); printf "It"s been %d seconds since later.\n", $later->(); It"s been 30 seconds since early. It"s been 10 seconds since later. Каждый вызов timestamp генерирует и возвращает новую функцию. Функция timestamp создает лексическую переменную $start_time, которая содержит текущее время (в секундах с начала эпохи). При каждом вызове замыкания оно возвращает количество прошедших секунд, которое определяется вычитанием начального времени из текущего.