Perl 将参数传递给子例程不起作用

Perl Passing arguments to subroutine not working

我正在尝试将参数传递给 perl 子例程,但无论出于何种原因,子例程中的参数都为空。

...
...
...
print "Passing arguments $a, $b, $c, $d \n";
beforeEnd($a, %b, $c, $d);

sub beforeEnd() {
    my ($a, %b, $c, $d) = @_;
    print "a is $a, b is $b, c is $c, d is $d \n";
}

打印语句的输出让我知道出了什么问题。奇怪的部分?前 2 个参数正确传递。

> Passing arguments 1, (1,2,3), 2, 3
> a is 1, b is (1,2,3), c is , d is

如有任何帮助,我们将不胜感激。

当参数传递给 Perl 子例程时,它们被展平到一个由 @_ 表示的列表中。从概念上讲,这意味着如果您不传递对数组或散列的引用,您将 "lose" 一些数据。 "Lose" 不完全正确,因为所有数据仍然存在;它只是不在您期望的变量中。例如:

sub f {
   my (@a, @b) = @_;

   say 'a: ' . join(', ', @a);
   say 'b: ' . join(', ', @b);
}
f( qw(1 2 3), qw(a b c) );

您将得到以下输出:

a: 1, 2, 3, a, b, c
b: 

这是因为第一个数组 @a 消耗了 @_ 中的所有值,并且没有更多的值可以存储在 @b 中。您的 beforeEnd 子例程中的散列也发生了同样的事情。 $c$d 的值存储在 %b 中。作为一个例子,因为我看不到变量值,如果你通过

beforeEnd(1, ( a => 1, b => 2 ), 'c', 3);

在你的潜艇里面,你会得到这样的东西:

$a = 1
%b = ( a => 1, b => 2, c => 3 )
$c = undef
$d = undef 

您可以通过传递对哈希 %b 的引用来解决此问题:

beforeEnd($a, \%b, $c, $d);

因为当您将参数传入或传出子例程时,任何散列和数组都会被粉碎。

您正在向 %b 赋值,这将吞噬所有参数。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

sub test1 {
    my ( $first, @rest, $last ) = @_;

    print Dumper \@rest;

    print "First = $first, last = $last, rest = @rest\n";
}

sub test2 { 
   my ( $first, $second ) = @_;
   print "@$first ; @$second"; 
}

test1 ( 1, 2, 3, 4 ); 
test2 ( [1,2], [ 3,4] );

my @list1 = ( 1,2,3,4 );
my @list2 = ( 5,6,7,8 );

test1 ( @list1, @list2 );
test2 ( \@list1, \@list2 );

如果您想保持数组或散列的完整性,您需要通过引用或将它们作为最后一个参数传递。

如果您在此处打开 strictwarnings,您也可能会收到警告 - 这是强烈推荐的原因之一 - 因为 $b%b 不一样。您还会收到关于作业数量为奇数的警告:

Odd number of elements in hash assignment at line 5.
Use of uninitialized value $b in print

子例程接受标量列表作为参数。如果传递数组或散列,则会传递数组或散列的内容。也就是说

f($a, %b, $c, $d)

相同
f($a, $b_key_1, $b_val_1, $b_key_2, $b_val_2, $b_key_3, $b_val_3, $c, $d);

@_ 中有多少个标量应分配给 %b? Perl 保持简单并分配所有剩余的标量,所以

my ($a, %b, $c, $d) = @_;

真的和

没什么区别
my $a = $_[0];        # The first argument
my %b = @_[1..$#_];   # All but the first argument
my $c;
my $d;

最好传递对散列的引用。这样就避免了这个问题,而且效率更高。

use Data::Dumper qw( Dumper );

sub beforeEnd {
    my ($a, $b, $c, $d) = @_;
    local $Data::Dumper::Terse = 1;
    print "a is $a, b is ".Dumper($b).", c is $c, d is $d \n";
}

beforeEnd($a, \%b, $c, $d);

关于您的代码的离题评论:

  • 你有一个原型表明不需要参数 (),但你需要四个。摆脱那个原型。

  • 您应该避免使用 $a$b 作为变量,因为它可能会导致 sort.

参数只能作为标量变量列表在子例程中传递。

每当将参数传递给子例程时,我们都需要传递散列(或数组、对象)的引用。 ... ... ... 打印"Passing arguments $a, $b, $c, $d \n"; beforeEnd($a, \%b, $c, $d);

sub beforeEnd() {
    my ($a, $b, $c, $d) = @_;
    print "a is $a, b is %$b, c is $c, d is $d \n";
}