Ссылка на массив создается следующим образом:
$aref = \@аrrау;
$anon_array = [1, 3, 5, 7, 9];
$anon_copy = [ @аrrау ];
@$implicit_creation = (2, 4, 6, 8, 10); Чтобы разыменовать ссылку на массив, поставьте перед ней символ @:
push(@$anon_array, 11);
Или воспользуйтесь стрелкой с указанием индекса конкретного элемента в квадратных скобках:
$two = $implicit_creation->[0]; Для получения индекса последнего элемента массива по ссылке или определения количества элементов в массиве применяется следующая запись:
$last_idx = $#$aref;
$num_items = @$aref; Дополнительные фигурные скобки повышают надежность и форсируют ну/к ный контекст:
$last_idx = $#{ $aref };
$num_items = scalar @{ $aref };
С каждым ключом хэша может быть ассоциирована лишь одна скалярная величина, однако вам хочется использовать один ключ для хранения и извлечения нескольких величин. Иначе говоря, вы хотите, чтобы ассоциированное значение представляло собой список.
Решение
Сохраните в элементе хэша ссылку на массив. Используйте push для присоединения новых элементов:
push(@{ $hash{"KEYNAME"} }, "new value");
Затем при выводе хэша разыменуйте значение как ссылку на массив:
foreach $string (keys %hash) {
print "$string: @{$hash{$string}}\n";
Комментарий
В хэше могут храниться только скалярные величины. Впрочем, ссылки и являются скалярными величинами. Они помогают решить проблему сохранения не-
скольких ассоциированных значений с одним ключом - в $hash{$key} помещается ссылка на массив, содержащий значения $key. Все стандартные операции с хэшами (вставка, удаление, перебор и проверка существования) могут комбинироваться с операциями массивов (pu
Присвоение ключу нескольких значений осуществляется следующим образом:
$hash{"a key"} = [ 3, 4, 5 ]; # Анонимный массив Ключ с ассоциированным массивом используется так:
lvalues = @{ $hash{"a key"} }; Для присоединения новых значений к массиву, ассоциированному с конкретным ключом, используется функция push:
push @{ $hash{"a key"} }, $value; Классическое применение этой структуры данных - инвертирование хэша, в котором одно значение ассоциируется с несколькими ключами. В хэше, полученном после инвертирования, один ключ ассоциирован с несколькими значениями. Эта проблема рассматривается в
Учтите, что запись вида:
Presidents = @{ $phone2name{$number} }; при действующей директиве use st rict вызовет исключение, поскольку вы пы та-етесь разыменовать неопределенную ссылку без автоматического создания. Приходится использовать другую формулировку:
@residents = exists( $phone2name{$number} ) ? @{ $phone2name{$number} } : О;}
> Смотри также ------------------------------
Раздел "Hashes of Arrays" perldsc(1); рецепт 5.8; пример "Хэш с автоматическим дополнением" из рецепта 13.15.
Требуется работать с хэшем по ссылке. Например, ссылка может передаваться ф} ции или входить во внешнюю структуру данных.
Решение
Получение ссылки на хэш:
$href = \%hash;
$anon_hash = { "key1" => "valuel", "key2" => "value2 ..." };
$anon_hash_copy = { %hash };
Разыменование ссылки на хэш:
%hash = %$href;
$value = $href->{$key};
@slice = @$href{$key1, $key2, $key3}; # Обратите внимание: стрелки нет!
@keys = keys %$hash; Проверка того, является ли переменная ссылкой на хэш:
if (ref($someref) ne 'HASH') {
die "Expected a hash reference, not $someref\n";
}
Комментарий
Следующий пример выводит все ключи и значения двух заранее определенных хэшей:
foreach $href ( \%ENV, \%INC ) { # ИЛИ:
for $href ( \(%ENV,%INC) ) { foreach $key ( keys %$href ) {
print "$key => $href->{$key}\n";
}
} Операции со срезами хэшей по ссылке выполняются так же, как со срезами массивов. Например:
@values = @$hash_ref{"key1", "key2", "key3"};
for $val (@$hash_ref{"key1", "key2", "key3"}) {
$val += 7; # Прибавить 7 к каждому значению в срезе хэша
}
[> Смотри также
Глава 5 "Хэши"; perlref(1), рецепт 11.9.
Требуется создать ссылку для вызова подпрограммы. Такая задача возникает при создании обработчиков сигналов, косвенно-вызываемых функций Tk и указателей па хэши функций.
Решение
Получение ссылки на функцию:
$cref = \&func;
$cref = sub { ... }; Вызов функции по ссылке:
@returned = $cref->(@arguments);
@oreturned = &$cref(@arguments);
Комментарий
Чтобы получить ссылку на функцию, достаточно снабдить ее имя префиксом Кроме того, формулировка sub {} позволяет создавать анонимные функции. Ссылка на анонимную функцию может быть сохранена так же, как и любая другая.
В Perl 5.004 появилась постфиксная запись для разыменования ссылок на функции. Чтобы вызвать функцию по ссылке, раньше приходилось писать &$funcname (@ARGS), где $funcname - имя функции. Возможность сохранить имя функции в переменной осталась и сейчас:
$funcname = "thefunc";
&$funcname(); однако подобное решение нежелательно по нескольким причинам. Во-первых, в нем используются символические, а не настоящие (жесткие) ссылки, поэтому при действующей директиве use st rict ' refs' оно отпадает. Символические ссылки обычно не рекомендуются
Во-вторых, оно не содержит данных о пакете, поэтому выполнение фрагмента в другом пакете может привести к вызову неверной функции. Наконец, если функция была в какой-то момент переопределена (хотя это происходит нечасто), символическая ссылка будет обраща
Вместо того чтобы сохранять имя функции в переменной, создайте ссылку на нее с помощью оператора \. Именно так следует сохранять функцию в переменной или передавать ее другой функции. Ссылки на именованные функции можно комбинировать со ссылками на аноним
my %commands = (
"happy" => \&joy,
"sad" => \&sullen,
"done" => sub { die "See ya!" },
"mad" => \&angry, );
print "How are you? ";
chomp($string = );
if ($commands{$string}) {
$comroands{$string}->();
} else {
print "No such command: $string\n";
}
Если вы создаете анонимную функцию, коюрая ссьыапся на лскшчесмю ( у) переменную из вмещающей области действия, схема подсчета ссылок гарантирует, что память лексической переменной не будет освобождена при наличии ссылок на нее:
sub counter_maker { my $start = 0;
return sub {
return $start++;
# Замыкание
# Лексическая переменная
# из вмещающей области действия
};
}
$counter = counter_maker();
for ($i = 0; $i < 5; $i ++) { print &$counter, "\n";
} Даже несмотря на то что функция counter_maker завершилась, а переменная $start вышла из области действия, Perl не освобождает ее, поскольку анонимная подпрограмма (на которую ссылается $counter) все еще содержит ссылку на $stan. Если повторно вызвать
$counter1 = counter_maker();
$counter2 = counter_maker();
for ($i =0; $i < 5; $i ++) { print &$counter1, "\n":
}
print &$counter1, " ", &$counter2, "\n";
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 = timestampO;
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, которая содержит текущее время (в секундах с начала эпохи). При каждом вызове замыкания оно возвращает количество прошедших сек
> Смотри также -------------------------------
Описание замыканий в perlref(1); рецепты 10.11; 11.4.
Требуется создать ссылку на скалярную величину и работать с ней.
Решение
Для создания ссылки на скалярную величину воспользуйтесь оператором \:
$scalar_ref = \$scalar; # Получение ссылки на именованный скаляр Чтобы создать ссылку на анонимную скалярную величину (то есть скаляр, не являющийся переменной), присвойте нужное значение через разыменование неопределенной переменной:
undef $anon_scalar_ref;
$$anon_scalar_ref = 15; Ссылка на скалярную константу создается следующим образом:
$anon_scalar_ref = \15; Разыменование выполняется конструкцией ${...}:
print ${ $scalar_ref }; # Разыменовать
${ $scalar_ref } .= "string"; # Изменить значение субъекта
Комментарий
Если вам понадобилось создать много новых анонимных скаляров, воспользуйтесь функцией, возвращающей ссылку на лексическую переменную вне области действия, как объяснялось во введении:
sub new_anon_scalar {
my $temp;
return \$temp;
} Perl почти никогда не выполняет косвенного разыменования. Исключение составляют ссылки на 4)айловые манипуляторы, программные ссылки на sort И ссылочный аргумент функции bless. Из-за этого для разыменования скалярнов переменной следует снабдить ее пре
$sref = new_anon_scalar();
$$sref = 3;
print "Three = $$sref\n";
@array_of_srefs = ( new_anon_scalar(), new_anon_scalar() );
${ $array[0] } = 6,02е23;
${ $аrrау[1] } = "avocado";
print "\@аrrау contains: ", join(", ", map { $$_ } @аrrау ), "\n";
Обратите внимание на фигурные скобки вокруг $аrrау[0] и $аrrау[1]. Если бы мы попытались ограничиться простым $$аrrау[0], то в процессе разыменования получили бы $аrrау->[0]. Переменная $аrrау интерпретировалась бы как ссылка на массив, поэтому в результа
Приведем другие примеры, в которых фигурные скобки необязательны:
$var = 'uptime'; # $var содержит текст
$vref = \$var; # $vref "указывает на"
$var if ($$vref =~ /load/) {} # Косвенное обращение к
$var chomp $$vref; # Косвенное изменение $var
Как упоминалось во введении, для определения типа субъекта по ссылке применяется встроенная функция ref. При вызове ref для ссылки на скаляр возвращается строка "SCALAR":
# Проверить, содержит ли $someref ссылку на скаляр
if (ref($someref) ne 'SCALAR') {
die "Expected a scalar reference, not $someref\n";
[> Смотри также -------------------------------
perlref(1).
Требуется создать массив ссылок на скаляры. Такая задача часто возникает при передаче функциям переменных по ссылке, чтобы функция могла изменить их значения.
Решение
Чтобы создать массив, либо снабдите префиксом \ каждый скаляр в списке:
@array_of_scalar_refs = ( \$а, \$b ); либо просто поставьте \ перед всем списком, используя свойство дистрибутивности оператора \:
@array_of_scalar_refs = \( $а, $b );
Чтобы получить или задать значение элемента списка, воспользуйтесь конструкцией ${...}:
${ $array_of_scalar_refs[1] } = 12; # $b = 12
Комментарий
В следующих примерах предполагается, что @аrrау - простой массив, содержащий ссылки на скаляры (не путайте массив ссылок со ссылкой на массив). При косвенных обращениях к данным необходимы фигурные скобки.
($а, $b, $c, $d) = (1 .. 4); # Инициализировать
@аrrау = (\$а, \$b, \$c, \$d); # Ссылки на все скаляры
@array = \( $а, $b, $c, $d); # То же самое!
${ $аrrау[2] } += 9; # $c = 12
${ $array[ $#аrrау ] } *= 5; # $d = 20
${ $аrrау[-1] } *= 5; # То же; $d = 100
$tmp = $array[-1]; # Использование временной переменной
$$tmp *= 5; #$d = 500
Две формы присваивания @аrray эквивалентны - оператор \ обладает свойством дистрибутивности. Следовательно, \ перед списком (но не массивом!) эквивалентно применению \ к каждому элементу списка. Следующий фрагмент изменяет значения переменных, ссылки на к
А вот как работать с массивом без явного индексирования.
use Math::Trig qw(pi); # Загрузить константу pi
foreach $sref (@array) { # Подготовиться к изменению $a,$b,$c,$d
($$sref **= 3) *= (4/3 * pi); # Заменить объемом сферы
} В этом фрагменте используется формула вычисления объема сферы:
V = 4/3pir Переменная цикла $s ref перебирает все ссылки @а г гау, а в $$s ref заносятся сами числа, то есть исходные переменные $а, $Ь, $с и $d. Изменение $$sref в цикле приводит к изменению этих переменных. Сначала мы возводим $$sref в куб, а затем умножаем по
Вообще говоря, анонимные скаляры обычно бесполезны - ведь скалярная B( -личина занимает столько же места, что и ссылка на нее. По этой причине не предусмотрены и специальные конструкции для их создания. Скалярные ссылки существуют только для поддержки син
> Смотри также -------------------------------
Раздел "Assignment Operators" perlop(1).