如何将哈希传递给Perl中的函数?
-
03-07-2019 - |
题
我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
sub PrintAA
{
my $test = shift;
my %aa = shift;
print $test . "\n";
foreach (keys %aa)
{
print 我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
<*> . " : " . $aa{我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
<*>} . "\n";
$aa{我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
<*>} = $aa{我有一个带变量和关联数组的函数,但我似乎无法让它们正确传递。我认为这与函数声明有关,但是我无法弄清楚它们在Perl中是如何工作的。对此有一个很好的参考,我如何实现我的需要?
我应该补充一点,它需要通过引用传递。
<*>} . "+";
}
}
解决方案
传递引用而不是哈希本身。如在
PrintAA("abc", \%fooHash);
sub PrintAA
{
my $test = shift;
my $aaRef = shift;
print $test, "\n";
foreach (keys %{$aaRef})
{
print 传递引用而不是哈希本身。如在
<*>
另见perlfaq7:如何传递/返回{Function,FileHandle,Array,Hash,Method,Regex}?
, " : ", $aaRef->{传递引用而不是哈希本身。如在
<*>
另见perlfaq7:如何传递/返回{Function,FileHandle,Array,Hash,Method,Regex}?
}, "\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 此代码有效:
my $test = shift;
my(%aa) = @_;
关键是在函数中my()'statement'中使用数组上下文。
数组上下文业务实际上做了什么?
简洁地说,它使它正常工作。
这意味着 @_
参数数组中的第一个值分配给 $ test
,其余项目分配给散列%aa 代码>。鉴于我调用它的方式, @_
中有一些奇数项,所以一旦将第一项分配给 $ test
,就会有一个偶数个可用于分配给%aa
的项目,每对中的第一项是键(在我的示例中为'aaa','bbb','ccc'),第二项是相应的值。
可以用 @aa
替换%aa
,在这种情况下,数组中将包含6个项目。也可以用 $ aa
替换%aa
,在这种情况下,变量 $ aa
将包含值'aaa' , @_
中的其余值将被赋值忽略。
如果省略变量列表周围的括号,Perl拒绝编译代码。
其中一个替代答案显示了符号:
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.
这几乎与我写的相同;不同之处在于,在两个 my
语句之后, @_
在此变体中只包含6个元素,而在单个 my
版本中,它仍然包含7个元素。
SO 关于数组上下文。
实际上,我没有询问 my($ test,%aa)= @_;
我问的是 my(%hash)=('aaa'=&gt ; 1,'bbb'=&gt;'球','ccc'=&gt; \&amp; PrintAA);
与 my%hash = {'aaa'=&gt; 1,...};
不同之处在于{...}表示法生成散列引用,而(...)表示法生成一个列表,该列表映射到散列(而不是散列引用)。同样,[...]生成一个数组引用,而不是一个数组。
确实,更改“主要”代码,使其显示为:my(%hash)= {...};并且你得到一个运行时(但不是编译时)错误 - 谨慎对待行号,因为我已经在我的文件中添加了替代编码:
<*> . " : " . $aa{此代码有效:
<*>
关键是在函数中my()'statement'中使用数组上下文。
数组上下文业务实际上做了什么?
简洁地说,它使它正常工作。
这意味着 @_
参数数组中的第一个值分配给 $ test
,其余项目分配给散列%aa 代码>。鉴于我调用它的方式, @_
中有一些奇数项,所以一旦将第一项分配给 $ test
,就会有一个偶数个可用于分配给%aa
的项目,每对中的第一项是键(在我的示例中为'aaa','bbb','ccc'),第二项是相应的值。
可以用 @aa
替换%aa
,在这种情况下,数组中将包含6个项目。也可以用 $ aa
替换%aa
,在这种情况下,变量 $ aa
将包含值'aaa' , @_
中的其余值将被赋值忽略。
如果省略变量列表周围的括号,Perl拒绝编译代码。
其中一个替代答案显示了符号:
<*>
这几乎与我写的相同;不同之处在于,在两个 my
语句之后, @_
在此变体中只包含6个元素,而在单个 my
版本中,它仍然包含7个元素。
SO 关于数组上下文。
实际上,我没有询问 my($ test,%aa)= @_;
我问的是 my(%hash)=('aaa'=&gt ; 1,'bbb'=&gt;'球','ccc'=&gt; \&amp; PrintAA);
与 my%hash = {'aaa'=&gt; 1,...};
不同之处在于{...}表示法生成散列引用,而(...)表示法生成一个列表,该列表映射到散列(而不是散列引用)。同样,[...]生成一个数组引用,而不是一个数组。
确实,更改“主要”代码,使其显示为:my(%hash)= {...};并且你得到一个运行时(但不是编译时)错误 - 谨慎对待行号,因为我已经在我的文件中添加了替代编码:
<*>} . "\n";
}
}
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );
PrintAA("test", %hash);
关键是在函数中my()'statement'中使用数组上下文。
数组上下文业务实际上做了什么?
简洁地说,它使它正常工作。
这意味着 @_
参数数组中的第一个值分配给 $ test
,其余项目分配给散列%aa 代码>。鉴于我调用它的方式,
@_
中有一些奇数项,所以一旦将第一项分配给 $ test
,就会有一个偶数个可用于分配给%aa
的项目,每对中的第一项是键(在我的示例中为'aaa','bbb','ccc'),第二项是相应的值。
可以用 @aa
替换%aa
,在这种情况下,数组中将包含6个项目。也可以用 $ aa
替换%aa
,在这种情况下,变量 $ aa
将包含值'aaa' , @_
中的其余值将被赋值忽略。
如果省略变量列表周围的括号,Perl拒绝编译代码。 其中一个替代答案显示了符号:
<*>这几乎与我写的相同;不同之处在于,在两个 my
语句之后, @_
在此变体中只包含6个元素,而在单个 my
版本中,它仍然包含7个元素。
SO 关于数组上下文。
实际上,我没有询问
my($ test,%aa)= @_;
我问的是my(%hash)=('aaa'=&gt ; 1,'bbb'=&gt;'球','ccc'=&gt; \&amp; PrintAA);
与my%hash = {'aaa'=&gt; 1,...};
不同之处在于{...}表示法生成散列引用,而(...)表示法生成一个列表,该列表映射到散列(而不是散列引用)。同样,[...]生成一个数组引用,而不是一个数组。
确实,更改“主要”代码,使其显示为:my(%hash)= {...};并且你得到一个运行时(但不是编译时)错误 - 谨慎对待行号,因为我已经在我的文件中添加了替代编码:
<*>可替换地:
sub PrintAA
{
my $test = shift;
my %aa = @_;
print $test . "\n";
foreach (keys %aa)
{
print 可替换地:
<*>
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如Paul Tomblin的答案)。
. " : " . $aa{可替换地:
<*>
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如Paul Tomblin的答案)。
} . "\n";
$aa{可替换地:
<*>
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如Paul Tomblin的答案)。
} = $aa{可替换地:
<*>
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如Paul Tomblin的答案)。
} . "+";
}
}
你从根本上缺少的是关联数组不是单个参数(尽管关联数组引用是,如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最佳实践 样式指针,不得不说将参数传递给函数:
对任何具有三个以上参数的子例程使用命名参数的哈希
但是因为你只有两个,你可以逃脱;)直接传递它们:
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 "所有上述方法都有效,但这总是我喜欢这样做的方式:
PrintAA("test", %hash);
注意:我也改变了你的代码。 Perl的双引号字符串将&quot; $ test&quot;
解释为 $ test
的值,而不是实际的字符串'$ test'
,所以你不需要那么多。
s。
另外,我对原型的工作方式错了。要传递哈希,请使用:
PrintAA("test", %$ref_to_hash);
要打印哈希引用,请使用:
<*>
当然,现在你无法修改 $ ref_to_hash
引用的哈希,因为你正在发送一个副本,但你可以修改原始的%hash
,因为你把它作为参考传递。
: $aa{所有上述方法都有效,但这总是我喜欢这样做的方式:
<*>
注意:我也改变了你的代码。 Perl的双引号字符串将&quot; $ test&quot;
解释为 $ test
的值,而不是实际的字符串'$ test'
,所以你不需要那么多。
s。
另外,我对原型的工作方式错了。要传递哈希,请使用:
<*>
要打印哈希引用,请使用:
<*>
当然,现在你无法修改 $ ref_to_hash
引用的哈希,因为你正在发送一个副本,但你可以修改原始的%hash
,因为你把它作为参考传递。
}\n";
$aa{所有上述方法都有效,但这总是我喜欢这样做的方式:
<*>
注意:我也改变了你的代码。 Perl的双引号字符串将&quot; $ test&quot;
解释为 $ test
的值,而不是实际的字符串'$ test'
,所以你不需要那么多。
s。
另外,我对原型的工作方式错了。要传递哈希,请使用:
<*>
要打印哈希引用,请使用:
<*>
当然,现在你无法修改 $ ref_to_hash
引用的哈希,因为你正在发送一个副本,但你可以修改原始的%hash
,因为你把它作为参考传递。
} = "$aa{所有上述方法都有效,但这总是我喜欢这样做的方式:
<*>
注意:我也改变了你的代码。 Perl的双引号字符串将&quot; $ test&quot;
解释为 $ test
的值,而不是实际的字符串'$ test'
,所以你不需要那么多。
s。
另外,我对原型的工作方式错了。要传递哈希,请使用:
<*>
要打印哈希引用,请使用:
<*>
当然,现在你无法修改 $ ref_to_hash
引用的哈希,因为你正在发送一个副本,但你可以修改原始的%hash
,因为你把它作为参考传递。
}+";
}
}
注意:我也改变了你的代码。 Perl的双引号字符串将&quot; $ test&quot;
解释为 $ test
的值,而不是实际的字符串'$ test'
,所以你不需要那么多。
s。
另外,我对原型的工作方式错了。要传递哈希,请使用:
<*>要打印哈希引用,请使用:
<*>当然,现在你无法修改 $ ref_to_hash
引用的哈希,因为你正在发送一个副本,但你可以修改原始的%hash
,因为你把它作为参考传递。
将函数的参数展平为单个数组(@_)。因此,通过引用传递哈希值通常是最容易的。
创建HASH:
my %myhash = ( key1 => "val1", key2 => "val2" );
创建对该HASH的引用:
my $href = \%myhash
通过引用访问该哈希;
%$href
所以在你的潜艇中:
my $myhref = shift;
keys %$myhref;
到目前为止,所有其他回复对我来说都相当复杂。当我写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
&quot; swallows&quot;所有其他参数,总是将一个解释为一个键,将下一个解释为值(直到所有元素都用完为止)。
你不能以这种方式传递多个哈希,并且哈希不能是第一个参数,否则它会吞下所有内容并使所有其他参数保持未分配状态。
当然,数组与最后一个参数完全相同。这里唯一的区别是数组不区分键和值,因为剩下的所有参数都是值,只是被推送到数组。
使用下面的sub来获取hash或hashref - 无论传递什么:)
sub get_args { ref( 使用下面的sub来获取hash或hashref - 无论传递什么:)
printAA($firstarg,somearg=>1, anotherarg=>2)
按照以下方式调用您的函数:
printAA($firstarg,{somearg=>1, anotherarg=>2})
或者像这样(不管):
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );
PrintAA("test", %hash);
或者甚至喜欢这样(不管):
<*>
干杯!
[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
my $test = shift;
my $aa = get_args(@_);;
#then
$aa->{somearg} #do something
$aa->{anotherearg} #do something
}
按照以下方式调用您的函数:
<*>或者像这样(不管):
<*>或者甚至喜欢这样(不管):
<*>干杯!