[英]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.