簡體   English   中英

如何將哈希傳遞給 Perl 中的函數?

[英]How do I pass a hash to a function in Perl?

我有一個函數需要一個變量和一個關聯數組,但我似乎無法讓它們正確通過。 我認為這與函數聲明有關,但是我無法弄清楚它們在 Perl 中是如何工作的。 對此是否有很好的參考,我如何完成我需要的工作?

我應該補充一點,它需要通過引用傳遞。

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

傳遞引用而不是散列本身。 如在

PrintAA("abc", \%fooHash);

sub PrintAA
{
  my $test = shift;
  my $aaRef = shift;

  print $test, "\n";
  foreach (keys %{$aaRef})
  {
    print $_, " : ", $aaRef->{$_}, "\n";
  }
}

另請參閱 perlfaq7: 如何傳遞/返回 {Function, FileHandle, Array, Hash, Method, Regex}?

此代碼有效:

#!/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() '語句' 中使用數組上下文。


數組上下文業務實際上是做什么的?

簡而言之,它使它正常工作。

這意味着@_參數數組中的第一個值分配給$test ,其余項分配給哈希%aa 鑒於我的調用方式, @_有奇數個項目,因此一旦將第一個項目分配給$test ,就有偶數個項目可分配給%aa ,每個項目的第一個項目pair 是鍵(在我的示例中為 'aaa'、'bbb'、'ccc'),第二個是相應的值。

可以用@aa替換%aa ,在這種情況下,數組中將有 6 個項目。 也可以用$aa替換%aa ,在這種情況下,變量$aa將包含值 'aaa',@ @_的其余值將被賦值忽略。

如果省略變量列表周圍的括號,Perl 將拒絕編譯代碼。 替代答案之一顯示了符號:

my $test = shift;
my(%aa) = @_;

這和我寫的差不多; 不同的是,在兩個my語句之后,@ @_在這個變體中只包含 6 個元素,而在單個my版本中,它仍然包含 7 個元素。

SO中肯定還有其他關於數組上下文的問題。


實際上,我不是在問my($test, %aa) = @_; 我在問my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \\&PrintAA ); my %hash = { 'aaa' => 1, ... };

不同之處在於 { ... } 表示法生成一個散列引用,而 ( ... ) 表示法生成一個列表,該列表映射到一個散列(與散列引用相反)。 類似地, [ ... ] 生成一個數組 ref 而不是一個數組。

實際上,更改“主要”代碼,使其顯示為: my(%hash) = { ... }; 並且您會收到運行時(但不是編譯時)錯誤 - 請謹慎對待行號,因為我已將替代編碼添加到我的文件中:

Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.

或者:

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

您從根本上缺少的是關聯數組不是單個參數(盡管關聯數組引用是,如 Paul Tomblin 的回答)。

看起來您應該傳入對哈希的引用。

sub PrintAA
{
   my $test = shift;
   my $aa = shift;
   if (ref($aa) != "HASH") { die "bad arg!" }
   ....
}

PrintAA($foo, \%bar);

你不能做的原因

my %aa = shift;

是因為 Perl 將子例程的所有參數扁平化到一個列表中,@_。 每個元素都被復制,因此通過引用傳入也避免了這些副本。

像往常一樣,有幾種方法。 這是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 ...
}

如果您可以顯示一些代碼,它可能會更有用。

以前答案中的所有方法都有效,但這始終是我喜歡做這樣的事情的方式:

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

注意:我也稍微更改了您的代碼。 Perl的雙引號字符串將解釋"$test"是價值$test ,而不是實際的字符串'$test' ,所以你不需要很多做. s。

此外,我對原型如何工作的看法是錯誤的。 要傳遞哈希,請使用以下命令:

PrintAA("test", %hash);

要打印哈希引用,請使用以下命令:

PrintAA("test", %$ref_to_hash);

當然,現在您不能修改$ref_to_hash引用的散列,因為您正在發送副本,但是您可以修改原始%hash因為您將它作為引用傳遞。

函數的參數被扁平化為單個數組 ( @_ )。 因此,通過引用將哈希值傳遞給函數通常是最容易的。

創建哈希

my %myhash = ( key1 => "val1", key2 => "val2" );

要創建對該哈希的引用:

my $href = \%myhash

通過引用訪問該哈希;

%$href

所以在你的子:

my $myhref = shift;

keys %$myhref;

到目前為止,這里的所有其他回復對我來說似乎都很復雜。 當我編寫 Perl 函數時,我通常在函數的第一行“擴展”所有傳遞的參數。

sub someFunction {
    my ( $arg1, $arg2, $arg3 ) = @_;

這類似於其他語言,您可以將函數聲明為

... someFunction ( arg1, arg2, arg3 )

如果你這樣做,並將散列作為最后一個參數傳遞,你會沒事的,沒有任何技巧或特殊的魔法。 例如:

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 “吞下”所有其他參數,總是將一個解釋為鍵,將下一個解釋為值(直到所有元素都用完)。

您不能以這種方式傳遞多個散列,並且散列不能作為第一個參數,否則它會吞下所有內容並使所有其他參數未分配。

當然,對於數組作為最后一個參數的工作方式完全相同。 這里唯一的區別是數組不區分鍵和值。 對他們來說,剩下的所有參數都是值,只是被推送到數組中。

使用以下子獲取哈希或哈希引用 - 無論傳遞的是什么:)

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM