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 ref, то оно возвращается без изменений. Если это был перегруженный объект, он превращается в код. Если это не может быть приведено в 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');