我正在尝试将参数传递给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";
}
打印语句的输出让我知道出了问题。奇怪的部分?前两个参数正确传递。
> Passing arguments 1, (1,2,3), 2, 3
> a is 1, b is (1,2,3), c is , d is
非常感谢任何帮助。
答案 0 :(得分:2)
因为当您将参数传入或传出子例程时,任何哈希值和数组都会被打破。
您正在分配到%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 );
如果要保持数组或哈希值不变,则需要通过引用或最后一个参数传递它们。
如果您在此处启用了strict
和warnings
,也可能会收到警告 - 这是强烈建议的原因之一 - 因为$b
和%b
是不一样。您还会收到有关奇数分配的警告:
Odd number of elements in hash assignment at line 5.
Use of uninitialized value $b in print
答案 1 :(得分:1)
当参数传递给Perl子例程时,它们被展平为由@_
表示的单个List。从概念上讲,这意味着如果你没有传递对数组或哈希的引用,你将失去"一些数据。 "输"是不完全正确的,因为所有的数据仍然存在;它只是不在你期望的变量中。这方面的一个例子可能是:
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);
答案 2 :(得分:1)
子例程接受标量列表作为参数。如果传递数组或散列,则会传递数组或散列的内容。这意味着
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
有关。
答案 3 :(得分:0)
参数只能作为标量变量列表在子程序中传递。
每当将参数传递给子例程时,我们都需要传递散列(或数组,对象)的引用。 ... ... ... print“传递参数$ 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";
}