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

Alf*_*ons 10 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";
}
Run Code Online (Sandbox Code Playgroud)

输出:

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.
Run Code Online (Sandbox Code Playgroud)

DVK*_*DVK 15

你需要传递每个数组作为参考,否则你@x在sub中会吞噬整个参数数组,留下@y一个空的arraay和$z一个undef值.

发生这种情况是因为逗号运算符 - 在列表上下文中 - 将把a @x, @y, $z变成一个单独的数组,该数组包含所有元素@x后跟所有元素,@y然后是值$z; 你@x在sub中将吞噬整个组合的参数数组,留下@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";

}
Run Code Online (Sandbox Code Playgroud)


Eri*_*rom 8

你需要使用参考:

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

Hello(\@x, \@y, $z);
Run Code Online (Sandbox Code Playgroud)

您还可以使用Perl的子例程原型来消除\呼叫站点:

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

Hello(@x, @y, $z);
Run Code Online (Sandbox Code Playgroud)

所述(\@\@$)原型告诉用户参数给编译器Hello将会对第三个参数上的前两个args数组参考上下文,并且标量上下文.原型不适用于参数验证,它们允许您编写与内置函数类似的子例程.在这种情况下,喜欢push.

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