Warm tip: This article is reproduced from serverfault.com, please click

其他-正确检测Perl子例程参数是否为数组

(其他 - Properly detecting if Perl subroutine argument is array)

发布于 2020-11-29 16:37:33

我想将库从Javascript移植到Perl,但是在检测数组参数时遇到了一些问题。

一个简化的示例(使用Javascript)看起来像这样:

const say = console.log;

function test(array, integer)
{
 if(Array.isArray(array))
 {
  say("First argument is array");
 }
 else
 {
  say("First argument is not array");
  array = [array];
 }
 for(let index = 0; index < array.length; ++index)
 {
  say(array[index]);
 }
 say("Second argument: ", integer);
 say("");
}

var a = ["foo", "bar"];
var t = "baz";
var i = 1024;

say("Testing on array");
test(a, i);

say("Testing on string");
test(t, i);

输出:

Testing on array
First argument is array
foo
bar
Second argument:  1024

Testing on string
First argument is not array
baz
Second argument:  1024

这是Perl版本:

use feature qw(say);

sub test 
{
 my ($text, $integer ) = @_;
 my (@array) = @_;  
 if(ref(@array) == "ARRAY") 
 {
  say("First argument is array");
 }
 else 
 {
  say("First argument is not array");
  @array = ($text);
 }
 for my $index (0 .. $#array)
 {
  say($array[$index]);
 }
 say("Second argument: ", $integer);     
}

my @a = ("foo", "bar");
my $t = "baz";
my $i = 1024;

say("Testing on array");
test(@a, $i);

say("Testing on string");
test($t, $i);

输出:

Testing on array
First argument is array
foo
bar
1024
Second argument: bar

Testing on string
First argument is array
baz
1024
Second argument: 1024

我还尝试了许多其他方法,例如在数组名称前加反斜杠等等,但都无济于事。我相当确定,这在Perl中必须是可能的。还是这是语言本身的某种局限性?

Questioner
Sir Galahad
Viewed
0
TLP 2020-11-30 01:14:16

Perl子例程不将数组作为参数,仅将标量作为参数。子调用中的数组折叠为标量列表。如果要传递数组,则有2个选项。

  1. 传递数组引用,例如test(\@a, $i)test([ @a ], $i)或者更好的方法是,先传递标量参数,然后将其余参数传递到数组中。
  2. 深入研究Perl原型,并学习它们的工作原理。

我建议采用解决方案1。通常,你可以执行以下操作

test($i, @a);

sub test {
    my $i = shift;
    my @a = @_;
    ....
}

或者

test($i, [ @a ]);

sub test {
    my $i = shift;
    my $aref = shift;
    my @a = @$aref;       # expand to normal array (not strictly needed)
    ....
}

请注意,将引用传递给数组@a将允许子控件更改数组中的值,因此将其作为匿名数组传递会[ @a ]更安全。

另外,代码:

my @a;
print ref(\@a);

将打印ARRAY,但不ref(@a)打印任何内容。

另外,如果你曾经使用过

use strict;
use warnings;

你会得到非常启发性的警告

Argument "ARRAY" isn't numeric in numeric eq (==) 

哪个告诉你在字符串比较中,应该使用eq而不是==数字。因为Perl会0在数值上下文中静默将空字符串转换为,并将字符串转换ARRAY0,比较的结果为true,这会使你的比较返回假阳性。

不使用strict不编写Perl代码warnings