Ответ 1
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');