каково использование

#perl

#perl

Вопрос:

 sub reduce(amp;@) {

    my $expr = amp;{shift @ARG};

    my $result = shift @ARG;
    while (scalar @ARG > 0) {
        our $a = $resu<
        our $b = shift @ARG;
        $result = $expr->();
    }

    return $resu<
}
  

Я не могу понять некоторую грамматику в этом коде. Кто-нибудь может мне объяснить? например amp; , и $result = $expr->()

Комментарии:

1. Я не специалист по perl, но я уверен $expr , что это ссылка на подпрограмму . Я полагаю amp;{shift @ARG} , что он преобразует первый аргумент в ссылку на подпрограмму и $expr->() вызовет эту подпрограмму. Обратите внимание, что он делает значения $a и $b доступными для подпрограммы как глобальные.

Ответ №1:

amp;name возвращает ссылку на подпрограмму с именем name .

$code_ref->() вызывает подпрограмму, на которую ссылается $code_ref .

 $ perl -e'
    sub f { CORE::say "Hi" }
    my $code_ref = amp;f;
    $code_ref->();
'
Hi
  

В вашем случае shift @ARG возвращает ссылку на подпрограмму. amp;{ $code_ref } просто возвращает ссылку на код. Как таковой,

 my $expr = amp;{shift @ARG};
  

можно было бы записать как

 my $expr = shift @ARG;
  

Обратите внимание, что reduce прототип позволяет вызывать его как

 reduce { ... } ...
  

но на самом деле выполняется

 reduce( sub { ... }, ... )
  

Обратите внимание, что эта версия reduce содержит ошибки. Вы должны использовать тот, который предоставлен List::Util .

  • local $a и local $b должен был использоваться, чтобы избежать искажения значений, которые его вызывающий может иметь в $a и $b .
  • Эта версия reduce ожидает, что ее обратный вызов будет скомпилирован в том же пакете, reduce что и она сама. В противном случае вспомогательный модуль обратного вызова не сможет просто использовать $a and $b .
  • Объявление переменных using our на самом деле совершенно бесполезно в этой версии, поскольку $a и $b освобождаются от use strict; проверок, а необъявленное использование $a и $b будет обращаться к тем же переменным пакета.

Комментарии:

1. как насчет наших переменных before ?

2. Они создают псевдонимы с лексической областью для переменных пакета $a и $b . Это означает, что если текущий пакет есть Foo , он создает псевдоним, вызываемый $a для переменной $Foo::a . Изменение одного приведет к изменению другого. К этим переменным будет обращаться указанная подпрограмма. Если my $a my $b бы использовались и, они создавали бы переменные, которые не могла видеть указанная подпрограмма.

Ответ №2:

Возможно, поможет просмотр некоторых примеров List::Util::reduce() .

Давайте рассмотрим первый:

 $foo = reduce { $a > $b ? $a : $b } 1..10;
  

Поэтому reduce принимает a BLOCK , за которым следует СПИСОК, который объявляется сигнатурой функции: sub reduce(amp;@) { . Блок в нашем случае — это оператор $a > $b ? $a : $b , а список — это 1..10 . Из документации:

Уменьшает @list, вызывая «BLOCK» в скалярном контексте несколько раз, каждый раз устанавливая $ a и $ b . Первый вызов будет с $ a и $ b, установленными для первых двух элементов списка, последующие вызовы будут выполняться путем установки $ a на результат предыдущего вызова и $ b на следующий элемент в списке.

Возвращает результат последнего вызова «БЛОКА». Если @list пуст, то возвращается «undef». Если @list содержит только один элемент, то этот элемент возвращается и «БЛОК» не выполняется.

А теперь перейдем к аннотированной версии кода:

 $foo = reduce { $a > $b ? $a : $b } 1..10;  # $foo will be set to 10

sub reduce(amp;@) {
    # reduce() takes a BLOCK followed by a LIST
    my $expr = amp;{shift @ARG};
    # $expr is now a subroutine reference, i.e.
    # $expr = sub { $a > $b ? $a : $b };

    # Start by setting $result to the first item in the list, 1
    my $result = shift @ARG;

    # While there are more items in the list...
    while (scalar @ARG > 0) {
        # Set $a to the current result
        our $a = $resu<

        # Set $b to the next item in the list
        our $b = shift @ARG;

        # Set $result to the result of $a > $b ? $a : $b
        $result = $expr->();
    }

    # List has now been reduced by the operation $a > $b ? $a : $b
    return $resu<
}