Как правильно вызвать подпрограмму, которая принимает 2 ссылки на подпрограмму? - PullRequest
3 голосов
/ 25 октября 2009

Представьте себе эту подпрограмму:

sub test(&&)
{
    my $cr1 = shift;
    my $cr2 = shift;
    $cr1->();
    $cr2->();
}

Я знаю, что могу назвать это как: test(\&sub1,\&sub2), но как я могу назвать это как:

test { print 1 },{ print 2 };

Если я скажу, что подпрограмма занимает только один &, то отправка блока будет работать. Я не знаю, как заставить это работать с 2.

Если я попытаюсь запустить его таким образом, я получу:

Not enough arguments for main::test at script.pl line 38, near "},"

РЕДАКТИРОВАТЬ: нет никакого способа вызвать без sub?

Ответы [ 4 ]

12 голосов
/ 25 октября 2009

Вы должны явно сказать

test( sub { print 1 }, sub { print 2 } );

или

test { print 1 } sub { print 2 };

Неявное «sub» доступно только для первого аргумента. http://perldoc.perl.org/perlsub.html#Prototypes:

Для & требуется анонимная подпрограмма, которая при передаче в качестве первого аргумента не требует ключевого слова sub или последующей запятой.

Некоторые вещи используют дополнительное слово, чтобы подделать его:

test { print 1 } against { print 2 };

sub against (&) { $_[0] }
sub test (&@) { ... }

но мне никогда так не нравилось.

8 голосов
/ 25 октября 2009

Вы можете сделать это:

test(sub { print 1 }, sub { print 2 });
1 голос
/ 26 октября 2009

Если вы действительно хотите изменить синтаксис больше, взгляните на Devel::Declare

Примеры модулей, которые используют Devel::Declare:

Полный список модулей на CPAN зависит на Devel :: Declare можно найти через CPANTS

Вот пример из Test :: Class :: Sugar pod :

use Test::Class::Sugar;

testclass exercises Person {
    # Test::Most has been magically included

    startup >> 1 {
        use_ok $test->subject;
    }

    test autonaming {
        is ref($test), 'Test::Person';
    }

    test the naming of parts {
        is $test->current_method, 'test_the_naming_of_parts';
    }

    test multiple assertions >> 2 {
        is ref($test), 'Test::Person';
        is $test->current_method, 'test_multiple_assertions';
    }
}

Test::Class->runtests;


А вот что-то сексуальное из PerlX :: MethodCallWithBlock pod :

use PerlX::MethodCallWithBlock;

Foo->bar(1, 2, 3) {
  say "and a block";
};


Devel :: Declare - гораздо более надежный и разумный способ искажения кода Perl по сравнению с использованием исходного фильтра, например Filter::Simple.

Вот видео от его автора, которое может помочь немного больше.

/ I3az /

1 голос
/ 25 октября 2009

В одной из моих программ есть следующий код:

sub generate($$$$)
{
    my ($paramRef, $waypointCodeRef, $headerRef,
        $debugCodeRef) = @_;
...
   &$headerRef();
...
       my $used = &$waypointCodeRef(\%record);

И я называю это с

CreateDB::generate(\%param, \&wayPointCode, \&doHeader, \&debugCode);
...