Perl предлагает систему, называемую прототипами подпрограмм, которая позволяет вам писать пользовательские подпрограммы, которые анализируются аналогично встроенным функциям. Встроенные функции, которые вы хотите эмулировать, — это map
, grep
или sort
, каждая из которых может принимать блок в качестве первого аргумента.
Чтобы сделать это с прототипами, вы используете sub name (&) {...}
, где &
сообщает Perl, что первым аргументом функции является либо блок (с sub
или без него), либо буквальная подпрограмма \&mysub
. Прототип (&)
указывает один и только один аргумент, если вам нужно передать несколько аргументов после блока кода, вы можете записать его как (&@)
, что означает блок кода, за которым следует список.
sub higher_order_fn (&@) {
my $code = \&{shift @_}; # ensure we have something like CODE
for (@_) {
$code->($_);
}
}
Эта подпрограмма будет запускать переданный блок для каждого элемента переданного списка. \&{shift @_}
выглядит немного загадочно, но он сдвигает первый элемент списка, который должен быть кодовым блоком. &{...}
разыменовывает значение как подпрограмму (вызывая любую перегрузку), а затем \
немедленно берет ссылку на него. Если значение было ссылкой CODE, то оно возвращается без изменений. Если это был перегруженный объект, он превращается в код. Если его нельзя преобразовать в CODE, выдается ошибка.
Чтобы вызвать эту подпрограмму, вы должны написать:
higher_order_fn {$_ * 2} 1, 2, 3;
# or
higher_order_fn(sub {$_ * 2}, 1, 2, 3);
Прототип (&@)
, который позволяет записывать аргумент в виде блока, подобного map
/grep
, работает только при использовании функции более высокого порядка в качестве функции. Если вы используете его как метод, вы должны опустить прототип и написать его так:
sub higher_order_method {
my $self = shift;
my $code = \&{shift @_};
...
$code->() for @_;
}
...
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here');
person
Eric Strom
schedule
23.05.2011
($)
может означать не то, что вы думаете. Это означает дать мне один аргумент, но это также означает наложение скалярного контекста на этот аргумент. Таким образом, если у вас есть массив с одним элементом в нем, и вы вызвалиfoo_1 @array
, тоfoo_1
будет передано число1
, которое является количеством элементов в массиве. Чтобы на самом деле получить первый аргумент, вам нужно будет вызвать его какfoo_1 $array[0]
. Если бы у вас не было прототипа, то вы могли бы назвать его какfoo_1 @array
и он работал бы правильно. - person Eric Strom   schedule 24.05.2011@_ == 1 or die "function takes 1 argument"
в верхней части подпрограммы. - person Eric Strom   schedule 24.05.2011