如何将哈希传递给子例程?
Posted
技术标签:
【中文标题】如何将哈希传递给子例程?【英文标题】:How do I pass a hash to subroutine? 【发布时间】:2011-06-21 01:21:24 【问题描述】:需要帮助弄清楚如何做到这一点。我的代码:
my %hash;
$hash'1'= 'Make' => 'Toyota','Color' => 'Red',;
$hash'2'= 'Make' => 'Ford','Color' => 'Blue',;
$hash'3'= 'Make' => 'Honda','Color' => 'Yellow',;
&printInfo(%hash);
sub printInfo
my (%hash) = %_;
foreach my $key (keys %_
my $a = $_$key'Make';
my $b = $_$key'Color';
print "$a $b\n";
【问题讨论】:
【参考方案1】:当代码演变时可能会导致问题的简单方法是将默认数组@_(包含所有键值对作为偶数列表)分配给 %hash,然后相应地重建。所以你的代码看起来像这样:
sub printInfo
my %hash = @_;
...
更好的方法是将散列作为对子例程的引用。这样您仍然可以将更多参数传递给您的子例程。
printInfo(\%hash);
sub PrintInfo
my %hash = %$_[0];
...
在Perl中使用引用的介绍可以在perlreftut中找到
【讨论】:
第二个选项是最好的方法。【参考方案2】:你们非常非常亲近。没有%_
用于传递哈希,它必须在@_
中传递。幸运的是,哈希是使用列表上下文分配的,所以
sub printInfo
my %hash = @_;
...
会成功的!
还要注意,在大多数情况下,在子例程调用前使用&
是不必要的,至少从 Perl 5.000 开始。您可以像现在在其他语言中一样调用 Perl 子例程,只需使用名称和参数。 (正如@mob 在 cmets 中指出的那样,在某些情况下这仍然是必要的;如果有兴趣,请参阅 perlsub 以进一步了解这一点。)
【讨论】:
&
通常是可选的,并且(通常)不是最佳实践,因为 Perl 生成默认参数的方式,但它并未被弃用。有时它是必需的,有时它不是必需的,但它仍然可以使代码更具可读性。
您,先生,在技术上是正确的:最好的正确。我已经澄清了我对此的评论。
不是“而且可能更老”。 &
仍然通常在 1993 年 2 月 5 日的最后一个 perl4 版本 4.036 中的函数调用中需要。相信我,我在那里。 ☺ 避免它的唯一方法是使用do mysubname()
语法——顺便说一句,它仍然可以正常工作,这让少数偶然发现它的人感到惊讶。或者超过它。
@mob &subname
仍用于defined
和undef
参数,或` \\ ` 或goto
运算符的操作数。对于调用,它用于绕过原型检查。 &foo()
对你的 @_
很友好,而没有括号的 &foo
是隐秘的。 goto &foo
对于尾递归可能更清晰,但你不能从那里到这里。【参考方案3】:
传递哈希和数组的最佳方式是reference。引用只是将复杂数据结构作为单个数据点进行讨论的一种方式——可以存储在标量变量中(如$foo
)。
阅读references,了解如何创建引用并取消引用引用以获取原始数据。
基础知识:在数据结构前面加上反斜杠以获取对该结构的引用。
my $hash_ref = \%hash;
my $array_ref = \@array;
my $scalar_ref = \$scalar; #Legal, but doesn't do much for you...
引用是原始结构的内存位置(加上有关结构的线索):
print "$hash_ref\n";
将打印如下内容:
HASH(0x7f9b0a843708)
要将引用恢复为可用格式,只需将引用放入正确的 sigil 前面:
my %new_hash = % $hash_ref ;
您应该了解如何使用引用,因为这是您可以在 Perl 中创建极其复杂的数据结构的方式,以及面向对象的 Perl 的工作原理。
假设您想将三个哈希传递给您的子例程。以下是三个哈希:
my %hash1 = ( this => 1, that => 2, the => 3, other => 4 );
my %hash2 = ( tom => 10, dick => 20, harry => 30 );
my %hash3 = ( no => 100, man => 200, is => 300, an => 400, island => 500 );
我将为他们创建参考
my $hash_ref1 = \%hash1;
my $hash_ref2 = \%hash2;
my $hash_ref3 = \%hash3;
现在只需传递引用:
mysub ( $hash_ref1, $hash_ref2, $hash_ref3 );
引用是标量数据,因此将它们传递给我的子程序没有问题:
sub mysub
my $sub_hash_ref1 = shift;
my $sub_hash_ref2 = shift;
my $sub_hash_ref3 = shift;
现在,我只是取消引用它们,我的子例程可以使用它们。
my %sub_hash1 = % $sub_hash_ref1 ;
my %sub_hash2 = % $sub_hash_ref2 ;
my %sub_hash3 = % $sub_hash_ref3 ;
您可以使用ref 命令查看引用是什么:
my $ref_type = ref $sub_hash_ref; # $ref_type is now equal to "HASH"
如果您想确保传递正确类型的数据结构,这很有用。
sub mysub
my $hash_ref = shift;
if ( ref $hash_ref ne "HASH" )
croak qq(You need to pass in a hash reference);
还要注意这些是内存引用,所以修改引用会修改原来的hash:
my %hash = (this => 1, is => 2, a => 3 test => 4);
print "$hashtest\n"; # Printing "4" as expected
sub mysub ( \%hash ); # Passing the reference
print "$hashtest\n"; # This is printing "foo". See subroutine:
sub mysub
my $hash_ref = shift;
$hash_ref->test = "foo"; This is modifying the original hash!
这可能很好 - 它允许您修改传递给子例程的数据,或者不好 - 它允许您无意修改传递给原始子例程的数据。
【讨论】:
【参考方案4】:我相信你想要
my %hash;
$hash'1'= 'Make' => 'Toyota','Color' => 'Red',;
$hash'2'= 'Make' => 'Ford','Color' => 'Blue',;
$hash'3'= 'Make' => 'Honda','Color' => 'Yellow',;
printInfo(%hash);
sub printInfo
my %hash = @_;
foreach my $key (keys %hash)
my $a = $hash$key'Make';
my $b = $hash$key'Color';
print "$a $b\n";
在printInfo(%hash)
行中,%hash
被扩展为具有交替键值对的列表。
在printInfo
中,@_
是这个列表,分配给%hash
它再次从列表中的交替元素创建具有相应值的键。
【讨论】:
【参考方案5】:您可以将它们传递为
-
参数列表
do_hash_thing( %hash )
对参数列表中哈希的引用
`do_hash_thing(@args_before, \%hash, @args_after)
作为 prototype 的参考,其工作方式类似于 keys
和其他哈希运算符。
列表如下:
sub do_hash_thing
my %hash = @_;
...
do_hash_thing( %hash );
这也允许你“流”散列参数:
do_hash_thing( %hash_1, %hash_2, parameter => 'green', other => 'pair' );
参考作品如下:
sub do_hash_thing
my $hash_ref = shift;
...
do_hash_thing( \%hash, @other_args );
这里是原型(\%@)
。原型使 perl 在第一个参数中查找哈希并通过引用传递它。
sub do_hash_thing (\%@)
my $hash_ref = shift;
...
do_hash_thing( %hash => qw(other args) );
# OR
do_hash_thing %hash => qw(other args);
警告:原型不适用于方法。
【讨论】:
(%)
是偶数长度列表,(\%)
是哈希参考以上是关于如何将哈希传递给子例程?的主要内容,如果未能解决你的问题,请参考以下文章
无法通过从两个不同子例程传递给新子例程的值来执行计算:Perl