正确检测 Perl 子例程参数是否为数组
Properly detecting if Perl subroutine argument is array
我正在尝试将库从 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 中一定是可能的。或者这可能是语言本身的某种限制?
Perl 子例程不将数组作为参数,仅将标量作为参数。子调用中的数组折叠成标量列表。如果你想传递一个数组,你有两个选择。
- 传递数组引用,例如
test(\@a, $i)
,或 test([ @a ], $i)
。或者更好的是,首先传递标量参数,然后将其余参数放入数组中。
- 深入研究 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
将允许 sub 更改数组中的值,因此将其作为匿名数组传递 [ @a ]
更安全。
另外,代码:
my @a;
print ref(\@a);
将打印 ARRAY
,但 ref(@a)
将不打印任何内容。
此外,如果您使用过
use strict;
use warnings;
你会得到非常有启发性的警告
Argument "ARRAY" isn't numeric in numeric eq (==)
这告诉你在字符串比较中,你应该使用 eq
而不是 ==
这是数字。因为 Perl 会默默地将空字符串转换为数字上下文中的 0
,并将字符串 ARRAY
转换为 0
,比较结果为真,这导致您比较 return 误报。
切勿在没有 strict
和 warnings
的情况下编写 Perl 代码。
我正在尝试将库从 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 中一定是可能的。或者这可能是语言本身的某种限制?
Perl 子例程不将数组作为参数,仅将标量作为参数。子调用中的数组折叠成标量列表。如果你想传递一个数组,你有两个选择。
- 传递数组引用,例如
test(\@a, $i)
,或test([ @a ], $i)
。或者更好的是,首先传递标量参数,然后将其余参数放入数组中。 - 深入研究 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
将允许 sub 更改数组中的值,因此将其作为匿名数组传递 [ @a ]
更安全。
另外,代码:
my @a;
print ref(\@a);
将打印 ARRAY
,但 ref(@a)
将不打印任何内容。
此外,如果您使用过
use strict;
use warnings;
你会得到非常有启发性的警告
Argument "ARRAY" isn't numeric in numeric eq (==)
这告诉你在字符串比较中,你应该使用 eq
而不是 ==
这是数字。因为 Perl 会默默地将空字符串转换为数字上下文中的 0
,并将字符串 ARRAY
转换为 0
,比较结果为真,这导致您比较 return 误报。
切勿在没有 strict
和 warnings
的情况下编写 Perl 代码。