开发者

How do I properly invoke a subroutine that takes 2 subroutine references?

Imagine this subroutine:

sub test(&&)
{
    my $cr1 = shift;
   开发者_运维问答 my $cr2 = shift;
    $cr1->();
    $cr2->();
}

I know I can call it like: test(\&sub1,\&sub2), but how can I call it like:

test { print 1 },{ print 2 };

If I say that the subroutine takes only one &, than sending a block will work. I don't know how to make it work with 2.

If I try to run it like that, I get:

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

EDIT: is there no way of invoking without sub?


You need to explicitly say

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

or

test { print 1 } sub { print 2 };

The implicit "sub" is only available for the first argument. http://perldoc.perl.org/perlsub.html#Prototypes:

An & requires an anonymous subroutine, which, if passed as the first argument, does not require the sub keyword or a subsequent comma.

Some things use an extra word in there to fake it:

test { print 1 } against { print 2 };

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

but I've never liked that much.


You can do this:

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


I've got the following code in one of my programs:

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

And I call it with

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


If you really want to bend the syntax more then take look at Devel::Declare

Examples of modules that use Devel::Declare:

  • MooseX::Declare (GitHub repo)
  • Test::Class::Sugar (GitHub repo)
  • PerlX::MethodCallWithBlock (GitHub repo)

Full list of modules on CPAN dependant on Devel::Declare can be found via CPANTS

Here is example from 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;


And here is something sexy from PerlX::MethodCallWithBlock pod:

use PerlX::MethodCallWithBlock;

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


Devel::Declare is a much more robust and saner way of contorting your Perl code compared to using a source filter like Filter::Simple.

Here is a video from its author which may help a bit more.

/I3az/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜