perl subs 什么时候将参数作为 `$_` 传递,什么时候是 `$_[0]` ?

KJ7*_*LNW 1 perl coderef

我注意到Parallel::Loops模块用作$_其 subref 的参数。这个问题与Parallel::Loops本身无关,而是与 coderef 调用约定有关。

这是他们的示例,请注意$_传递给子:

$pl->foreach( \@parameters, sub {
    # This sub "magically" executed in parallel forked child
    # processes
 
    # Lets just create a simple example, but this could be a
    # massive calculation that will be parallelized, so that
    # $maxProcs different processes are calculating sqrt
    # simultaneously for different values of $_ on different CPUs
    # (Do see 'Performance' / 'Properties of the loop body' below)
 
    $returnValues{$_} = sqrt($_);
});
Run Code Online (Sandbox Code Playgroud)

...但我总是使用$_[0]or@_作为传递给子组件的值:

$a = sub { print "\$_=$_\n" ; print "\$_[0]=$_[0]\n" };
$a->(1);

# prints out
# $_=
# $_[0]=1
Run Code Online (Sandbox Code Playgroud)

请注意,在我的示例中$_不起作用,但$_[0](ie, @_) 起作用。Parallel::Loops示例中的 coderef 和我的示例中的 coderef 有什么不同?

请注意,他们的示例不是拼写错误:它仅在您使用时才有效$_,这就是我提出这个问题的原因。

bri*_*foy 6

当您想知道它是如何做它的事情时,请查看模块源代码:)

在 中Parallel::Loops::foreach,模块$_在调用您提供的子例程之前进行设置。由于这是一个分叉进程,因此它不会做任何事情来保护 的值$_。请注意该模块中的各个代码引用层。

# foreach is implemented via while above
sub foreach {
    my ($self, $varRef, $arrayRef, $sub);
    if (ref $_[1] eq 'ARRAY') {
        ($self, $arrayRef, $sub) = @_;
    } else {
        # Note that this second usage is not documented (and hence not
        # supported). It isn't really useful, but this is how to use it just in
        # case:
        #
        # my $foo;
        # my %returnValues = $pl->foreach( \$foo, [ 0..9 ], sub {
        #     $foo => sqrt($foo);
        # });
        ($self, $varRef, $arrayRef, $sub) = @_;
    }
    my $i = -1;
    $self->while( sub { ++$i <= $#{$arrayRef} }, sub {
        # Setup either $varRef or $_, if no such given before calling $sub->()
        if ($varRef) {
            $$varRef = $arrayRef->[$i];
        } else {
            $_ = $arrayRef->[$i];
        }
        $sub->();
    });
}
Run Code Online (Sandbox Code Playgroud)

你也可以做同样的事情。每次要运行代码引用时,请设置$_第一个值:

for_all( [ qw(1 3 7) ], sub { print "$_\n" } );

sub for_all {
    my( $array, $sub ) = @_;

    foreach my $value ( @$array ) {
        local $_ = $value;
        $sub->();
        }
    }
Run Code Online (Sandbox Code Playgroud)

例如,看看Mojo::Collection ,它使用其代码引用来执行此操作。List::Util有几个实用程序也可以执行此操作。