如何将两个数组和一个字符串传递给Perl子例程?

时间:2010-10-21 19:26:05

标签: perl arguments

如何将两个数组和一个字符串传递给子?

这是我正在尝试做的事情:

use strict;
use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE);
my @y = qw(1111 2222 3333 4444 5555);

my $z = "hello";

Hello(@x,@y,$z);

exit(0);

sub Hello {

    my (@x,@y,$z) = @_;

    print "$_\n" for @x;
    print "$_\n";
    print "$_\n" for @y;
    print "$_\n";
    print "$z\n";
}

输出:

AAA
BBBB
CCCC
DDDD
EEEE
1111
2222
3333
4444
5555
hello
Use of uninitialized value $_ in concatenation (.) or string at test.pl line 19.

Use of uninitialized value $_ in concatenation (.) or string at test.pl line 21.

Use of uninitialized value $z in concatenation (.) or string at test.pl line 22.

4 个答案:

答案 0 :(得分:15)

您需要将每个数组作为参考传递,否则子中的@x将吞噬ENTIRE参数数组,使@y成为空的arraay并$z undef值。

这是因为the comma operator - 在列表上下文中 - 会将@x, @y, $z转换为由@x的所有元素组成的单个数组,后跟@y的所有元素然后是$z的值;子中的@x将吞噬整个参数数组,使@y为空数组,$z为undef值。

另一个可能的混淆源是你将两个变量命名为@x,尽管由于范围规则它们完全相互独立。好的做法是将它们命名为不同的东西,以避免猜测你打算使用哪一个,例如:调用子例程的第一个数组@x2

请注意,您可以通过以下两种方式之一传递数组作为参考 - 对原始数组的引用(真正的传递引用方法)以及对数组的COPY的引用 - 这将表现得像你希望你的原始代码能够表现并传递价值。

use strict; use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE); 
my @y = qw(1111 2222 3333 4444 5555);
my $z = "hello";

Hello(\@x,\@y,$z);

# If you wish to pass a reference of a COPY of the array, 
# so that you can modify it inside the subroutine without modifying the original,
# instead call Hello([@x], [@y], $z);

exit(0);

sub Hello {

    my ($x2,$y2,$z2) = @_;
    # Now, you de-reference array reference $x2 via @$x2 or $x2->[$i]
    # where previously you used @x2 or $x2[$i]
    print "$_\n" for @$x2;
    print "$_\n";
    print "$_\n" for @$y2;
    print "$_\n";
    print "$z2\n";

}

答案 1 :(得分:8)

你需要使用引用:

sub Hello {
   my ($x, $y, $z) = @_;
   print "$_\n" for @$x;
   ...
}

Hello(\@x, \@y, $z);

你也可以使用Perl的子程序原型消除呼叫站点的\

sub Hello (\@\@$) {...}

Hello(@x, @y, $z);

(\@\@$)原型告诉编译器Hello的参数将在前两个args上具有数组引用上下文,在第三个arg上具有标量上下文。原型不适用于参数验证,它们允许您编写与内置函数类似的子例程。在这种情况下,例如push

正如DVK在下面的评论中提到的那样,PBP建议不要使用原型作为一般规则,因为它们往往被不正确地用于参数验证。我觉得使用原型的某些功能(\%\@来强加多个类型的引用上下文,或者&作为第一个arg来允许map像块语法一样对齐打破PBP。特别正确的是,如果使用sub来扩展Perl的语法(辅助函数,只是语法糖的函数......)

答案 2 :(得分:3)

您需要传入数组引用:

sub Hello {
  my ( $x_ref, $y_ref, $z ) = @_;
  my @x = @$x_ref;
  my @y = @$y_ref;
  ...
}

Hello( \@x, \@y, $z );

答案 3 :(得分:1)

use strict; use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE); my @y = qw(1111 2222 3333 4444 5555);

my $z = "hello";

Hello(\@x,\@y,$z);

exit(0);

sub Hello {
    my ($x,$y,$z) = @_;

    print "$_\n" for @$x;
    print "$_\n" for @$y;
    print "$z\n";

}