Лучший способ немедленного вызова выражения функции (IIFE) в Perl? - PullRequest
2 голосов
/ 10 июня 2019

Заимствуя термин «Javascript», каков «лучший метод» для IIFE в perl?

Мой тестовый код, приведенный ниже, представляет собой простой цикл, вызывающий анонимную подпрограмму и выполняющий ее сразу же для создания массиваподпрограмм (которые просто возвращают индекс цикла).Это в основном то, что я хочу, однако мне нужно использовать промежуточную переменную (вместо использования @_, которая изменяется во внутренней функции).

use warnings;
use strict;
my @funcs;
for(my $i=0;$i<3;$i++) {
    sub  {
        my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}

for (@funcs) {
    print &$_()."\n";
}
#Output
0
1
2

Я знаю, что могу использовать map чтобы реструктурировать эту проблему.Но если оставить это в стороне, есть ли лучший способ сделать это?

Обновление

Спасибо @ikegami за выделение некоторых важных моментов.

Простодля будущих взглядов на этот вопрос, мои мысли об этом:

'Итератор' для цикла имеет другую область видимости (это карта?), чем 'стиль c' для цикла.Это очищает код без необходимости IIFE вообще.Sweet.

Обновление 2

Следующий код показывает различия, которые я вижу.Я не говорю, что одно лучше другого, но приятно знать.Вывод, который я ищу, равен 0 1 2, но первый повторяет только последнее значение $ i (3 после оператора ++).

use warnings;
use strict;
my @funcs;
print "C loop direct assignment of sub\n";
for(my $i=0;$i<3;$i++) {
    $funcs[$i]= sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop direct assignment of sub with variable\n";
for(my $i=0;$i<3;$i++) {
    my $index=$i; #assignment/copy
    $funcs[$index]= sub {$index};
}
print &$_()."\n" for @funcs;

print "For loop interator\n";
@funcs=[];
for my $i (0..2) {
    $funcs[$i]=sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop with IIFE assignment\n";
@funcs=[];
for (my $i=0;$i<3;$i++) {
    sub  {
    my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}
print &$_()."\n" for @funcs;

Выход:

C loop direct assignment of sub                                                                                                                                          
3                                                                                                                                                                        
3                                                                                                                                                                        
3         
C loop direct assignment of sub with variable                                                                                                                            
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                            
For loop interator                                                                                                                                                       
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                        
C loop with IIFE assignment                                                                                                                                                           
0                                                                                                                                                                        
1                                                                                                                                                                        
2        

1 Ответ

7 голосов
/ 11 июня 2019

Perl эквивалент

(function () {
   var x = ...;
   ...
})();

есть

sub {
   my $x = ...;
   ...
}->();

Тем не менее, IIFE - это просто обходной путь, который просто не нужен в Perl.

(function () {
   var x = ...;
   ...
})();

это обходной путь для

{
   my $x = ...;
   ...
}

и

var result = (function () {
   return ...;
})();

это обходной путь для

my $result = do {
   ...
};

Похоже, вы пытаетесь перевести что-то похожее на следующее:

let funcs = [];
for (let i=0; i<3; ++i) {
   (function() {
      var index = i;
      funcs.push( function() { return index; } );
   })();
}

for (let func of funcs)
   console.log(func());

Ниже приведен прямой перевод:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   sub {
      my $index = $i;
      push @funcs, sub { $index };
   }->();
}

say $_->() for @funcs;

Но просто нет смысла использовать IIFE. Можно было бы просто использовать следующее:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   my $index = $i;
   push @funcs, sub { $index };
}

say $_->() for @funcs;

Теперь можно избегать циклов в стиле C для Perl, потому что использование циклов foreach гораздо более читабельно (и более эффективно!). Это также делает решение еще проще, потому что переменная цикла цикла foreach ограничена телом цикла, а не областью оператора цикла.

my @funcs;
for my $i (0..2) {
   push @funcs, sub { $i };
}

say $_->() for @funcs;
...