如何将哈希传递给Perl中的函数?

时间:2009-04-29 19:08:34

标签: perl function parameter-passing declaration

我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?

我应该补充一点,它需要通过引用传递。

sub PrintAA
{
    my $test = shift;
    my %aa   = shift;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
        $aa{$_} = $aa{$_} . "+";
    }
}

9 个答案:

答案 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);

干杯!