我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
sub PrintAA
{
my $test = shift;
my %aa = shift;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
答案 0 :(得分:67)
传递引用而不是哈希本身。如在
PrintAA("abc", \%fooHash);
sub PrintAA
{
my $test = shift;
my $aaRef = shift;
print $test, "\n";
foreach (keys %{$aaRef})
{
print $_, " : ", $aaRef->{$_}, "\n";
}
}
另见perlfaq7:How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}?
答案 1 :(得分:16)
此代码有效:
#!/bin/perl -w
use strict;
sub PrintAA
{
my($test, %aa) = @_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
}
}
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );
PrintAA("test", %hash);
关键是在函数中my()'statement'中使用数组上下文。
数组上下文业务实际上做了什么?
简洁地说,它使它正常工作。
这意味着@_
参数数组中的第一个值分配给$test
,其余项目分配给散列%aa
。根据我调用它的方式,@_
中的项目数量奇数,因此一旦将第一个项目分配给$test
,就会有偶数项目可用于{{1}每个对的第一项是关键字('aaa','bbb','ccc'在我的例子中),第二项是相应的值。
可以用%aa
替换%aa
,在这种情况下,数组中将包含6个项目。也可以将@aa
替换为%aa
,在这种情况下,变量$aa
将包含值'aaa',$aa
中的其余值将包含被任务忽略。
如果省略变量列表周围的括号,Perl拒绝编译代码。 其中一个替代答案显示了符号:
@_
这几乎与我写的相同;不同之处在于,在两个my $test = shift;
my(%aa) = @_;
语句之后,my
在此变体中仅包含6个元素,而在单个@_
版本中,它仍包含7个元素。
SO中有关于数组上下文的其他问题。
实际上,我并没有问过
my
我询问的my($test, %aa) = @_;
与my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );
不同之处在于{...}表示法生成散列引用,而(...)表示法生成一个列表,该列表映射到散列(而不是散列引用)。同样,[...]生成一个数组引用,而不是一个数组。
确实,更改“主要”代码,使其显示为:my(%hash)= {...};并且你得到一个运行时(但不是编译时)错误 - 谨慎对待行号,因为我已经在我的文件中添加了替代编码:
my %hash = { 'aaa' => 1, ... };
答案 2 :(得分:12)
可替换地:
sub PrintAA
{
my $test = shift;
my %aa = @_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如Paul Tomblin的答案)。
答案 3 :(得分:4)
看起来你应该传入对哈希的引用。
sub PrintAA
{
my $test = shift;
my $aa = shift;
if (ref($aa) != "HASH") { die "bad arg!" }
....
}
PrintAA($foo, \%bar);
你不能做的原因
my %aa = shift;
是因为Perl将子例程的所有参数展平为一个列表@_。每个元素都被复制,因此通过引用传入也可以避免这些副本。
答案 4 :(得分:4)
像往常一样,有几种方法。以下是最受项目指针推崇的 Perl Best Practices ,不得不说将参数传递给函数:
对任何具有三个以上参数的子例程使用命名参数的哈希
但是因为你只有两个,你可以逃脱;)直接传递它们:
my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);
func($scalar, %hash)
功能定义如下:
sub func {
my $scalar_var = shift;
my %hash_var = @_;
... Do something ...
}
如果你能展示一些代码,那会更有用。
答案 5 :(得分:3)
所有上述方法都有效,但这总是我喜欢这样做的方式:
sub PrintAA ($\%)
{
my $test = shift;
my %aa = ${shift()};
print "$test\n";
foreach (keys %aa)
{
print "$_ : $aa{$_}\n";
$aa{$_} = "$aa{$_}+";
}
}
注意:我也改变了你的代码。 Perl的双引号字符串会将"$test"
解释为$test
的值,而不是实际的字符串'$test'
,因此您不需要那么多.
。
另外,我对原型的工作方式错了。要传递哈希,请使用:
PrintAA("test", %hash);
要打印哈希引用,请使用:
PrintAA("test", %$ref_to_hash);
当然,现在您无法修改$ref_to_hash
引用的哈希,因为您正在发送副本,但您可以修改原始%hash
,因为您将其作为参考传递。
答案 6 :(得分:1)
将函数的参数展平为单个数组(@_)。因此,通过引用传递哈希值通常是最容易的。
创建HASH:
my %myhash = ( key1 => "val1", key2 => "val2" );
创建对该HASH的引用:
my $href = \%myhash
通过引用访问该哈希;
%$href
所以在你的潜艇中:
my $myhref = shift;
keys %$myhref;
答案 7 :(得分:1)
到目前为止,所有其他回复对我来说都相当复杂。当我编写Perl函数时,我通常会“扩展”函数第一行中所有传递的参数。
sub someFunction {
my ( $arg1, $arg2, $arg3 ) = @_;
这与其他语言类似,您将函数声明为
... someFunction ( arg1, arg2, arg3 )
如果你这样做并将哈希作为最后一个参数传递,你将没有任何技巧或特殊魔法。 E.g:
sub testFunc {
my ( $string, %hash ) = @_;
print "$string $hash{'abc'} $hash{'efg'} $string\n";
}
my %testHash = (
'abc' => "Hello",
'efg' => "World"
);
testFunc('!!!', %testHash);
输出符合预期:
!!! Hello World !!!
这是因为Perl参数总是作为标量值数组传递,如果传递散列,它的键值/对将被添加到该数组中。在上面的示例中,作为数组(@_
)传递给函数的参数实际上是:
'!!!', 'abc', 'Hello', 'efg', 'World'
和'!!!'被简单地分配给%string
,而%hash
“吞下”所有其他参数,总是将一个解释为一个键,将下一个解释为值(直到所有元素都用完为止)。
你不能以这种方式传递多个哈希,并且哈希不能是第一个参数,否则它会吞下所有内容并使所有其他参数保持未分配状态。
当然,数组与最后一个参数完全相同。这里唯一的区别是数组不区分键和值,因为剩下的所有参数都是值,只是被推送到数组。
答案 8 :(得分:0)
使用下面的sub来获取hash或hashref - 无论传递什么:)
sub get_args { ref( $_[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
my $test = shift;
my $aa = get_args(@_);;
#then
$aa->{somearg} #do something
$aa->{anotherearg} #do something
}
按照以下方式调用您的函数:
printAA($firstarg,somearg=>1, anotherarg=>2)
或者像这样(不管):
printAA($firstarg,{somearg=>1, anotherarg=>2})
或者甚至喜欢这样(不管):
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );
PrintAA("test", %hash);
干杯!