How to run an anonymous function in Perl?

前端 未结 7 2010
长发绾君心
长发绾君心 2021-01-31 08:57
(sub {
print 1;
})();



sub {
print 1;
}();

I tried various ways, all are wrong...

相关标签:
7条回答
  • 2021-01-31 09:26

    You need arrow operator:

    (sub { print 1;})->();
    
    0 讨论(0)
  • 2021-01-31 09:26
    # ------------------------------------------------------
    # perl: filter array using given function
    # ------------------------------------------------------
    sub filter {
       my ($arr1, $func) = @_;
       my @arr2=();
       foreach ( @{$arr1} ) {
            push ( @arr2, $_ ) if $func->( $_ );
       };
       return @arr2;
    }
    
    # ------------------------------------------------------
    # get files from dir
    # ------------------------------------------------------
    sub getFiles{
     my ($p) = @_;
     opendir my $dir, $p  or die "Cannot open directory: $!";
     my @files=readdir $dir;
     closedir $dir;
     #return files and directories that not ignored but not links
     return filter \@files, (sub { my $f = $p.(shift);return ((-f $f) || (-d $f)) && (! -l $f) } ); 
    }
    
    0 讨论(0)
  • 2021-01-31 09:27

    You might not even need an anonymous function if you want to run a block of code and there is zero or one input. You can use map instead.

    Just for the side effect:

    map { print 1 } 1;
    

    Transform data, take care to assign to a list:

    my ($data) = map { $_ * $_ } 2;
    
    0 讨论(0)
  • 2021-01-31 09:44

    There is not much need in Perl to call an anonymous subroutine where it is defined. In general you can achieve any type of scoping you need with bare blocks. The one use case that comes to mind is to create an aliased array:

    my $alias = sub {\@_}->(my ($x, $y, $z));
    
    $x = $z = 0;
    $y = 1;
    
    print "@$alias"; # '0 1 0'
    

    Otherwise, you would usually store an anonymous subroutine in a variable or data structure. The following calling styles work with both a variable and a sub {...} declaration:

    dereference arrow:  sub {...}->(args)  or  $code->(args)
    
    dereference sigil:  &{sub {...}}(args) or &$code(args)
    

    if you have the coderef in a scalar, you can also use it as a method on regular and blessed values.

    my $method = sub {...};
    
    $obj->$method           # same as $method->($obj)
    $obj->$method(...)      # $method->($obj, ...)
    
    [1, 2, 3]->$method      # $method->([1, 2, 3])
    [1, 2, 3]->$method(...) # $method->([1, 2, 3], ...)
    
    0 讨论(0)
  • 2021-01-31 09:45

    Yay, I didn't expect you folks to come up with that much possibilities. But you're right, this is perl and TIMTOWTDI: +1 for creativitiy!

    But to be honest, I use hardly another form than the following:

    The Basic Syntax

    my $greet = sub {
        my ( $name ) = @_;
        print "Hello $name\n";
    };
    
    # ...
    
    $greet->( 'asker' )
    

    It's pretty straight forward: sub {} returns a reference to a sub routine, which you can store and pass around like any other scalar. You can than call it by dereferencing. There is also a second syntax to dereference: &{ $sub }( 'asker' ), but I personally prefer the arrow syntax, because I find it more readable and it pretty much aligns with dereferencing hashes $hash->{ $key } and arrays $array->[ $index ]. More information on references can be found in perldoc perlref.

    I think the other given examples are a bit advanced, but why not have a look at them:

    Goto

    sub bar {goto $foo};
    bar;
    

    Rarely seen and much feared these days. But at least it's a goto &function, which is considered less harmful than it's crooked friends: goto LABEL or goto EXPRESSION ( they are deprecated since 5.12 and raise a warning ). There are actually some circumstances, when you want to use that form, because this is not a usual function call. The calling function ( bar in the given example ) will not appear in the callling stack. And you don't pass your parameters, but the current @_ will be used. Have a look at this:

    use Carp qw( cluck );
    
    my $cluck = sub {
        my ( $message ) = @_;
        cluck $message . "\n";
    };
    
    
    sub invisible {
        @_ = ( 'fake' );
        goto $cluck;
    }
    
    invisible( 'real' );
    

    Output:

    fake at bar.pl line 5
        main::__ANON__('fake') called at bar.pl line 14
    

    And there is no hint of an invisible function in the stack trace. More info on goto in perldoc -f goto.

    Method Calls

    ''->$foo;
    # or
    undef->$foo;
    

    If you call a method on an object, the first parameter passed to that method will be the invocant ( usually an instance or the class name ). Did i already say that TIMTOWTCallAFunction?

    # this is just a normal named sub
    sub ask {
        my ( $name, $question ) = @_;
        print "$question, $name?\n";
    };
    
    my $ask = \&ask; # lets take a reference to that sub 
    
    my $question = "What's up";
    
    'asker'->ask( $question ); # 1: doesn't work
    
    my $meth_name = 'ask';
    'asker'->$meth_name( $question ); # 2: doesn't work either
    
    'asker'->$ask( $question ); # 1: this works
    

    In the snippet above are two calls, which won't work, because perl will try to find a method called ask in package asker ( actually it would work if that code was in the said package ). But the third one succeeds, because you already give perl the right method and it doesn't need to search for it. As always: more info in the perldoc I can't find any reason right now, to excuse this in production code.

    Conclusion

    Originally I didn't intend to write that much, but I think it's important to have the common solution at the beginning of an answer and some explanations to the unusual constructs. I admit to be kind of selfish here: Every one of us could end up maintaining someones code, who found this question and just copied the topmost example.

    0 讨论(0)
  • 2021-01-31 09:46

    (sub { ... }) will give you the pointer to the function so you must call by reference.

    (sub { print "Hello world\n" })->();

    The other easy method, as pointed out by Blagovest Buyukliev would be to dereference the function pointer and call that using the { } operators

    &{ sub { print "Hello World" }}();

    0 讨论(0)
提交回复
热议问题