Perl 如何将哈希传递给子例程?
我需要你帮我弄清楚怎么做。我的代码:Perl 如何将哈希传递给子例程?,perl,hash,subroutine,Perl,Hash,Subroutine,我需要你帮我弄清楚怎么做。我的代码: 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
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";
}
}
你非常非常接近。没有用于传递哈希的
%\uu
,它必须在@
中传递。幸运的是,哈希是使用列表上下文分配的,所以
sub printInfo {
my %hash = @_;
...
}
会成功的
另外请注意,在大多数情况下,在子例程调用之前使用&
是不必要的,因为至少是Perl 5.000。您可以像现在其他语言一样调用Perl子例程,只需名称和参数。(正如@mob在评论中指出的,在某些情况下,这仍然是必要的;如果有兴趣,请参阅以进一步了解这一点。)我相信您希望
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
它会从列表中的交替元素中再次创建具有相应值的键。简单的方法是分配默认数组,在代码演化时可能会导致问题(包含所有键-值对作为偶数列表)添加到%hash,然后重新生成相应的值。因此,您的代码如下所示:
sub printInfo {
my %hash = @_;
...
}
sub do_hash_thing {
my $hash_ref = shift;
...
}
do_hash_thing( \%hash, @other_args );
更好的方法是将哈希作为引用传递给子例程。这样,您仍然可以将更多参数传递给子例程
printInfo(\%hash);
sub PrintInfo {
my %hash = %{$_[0]};
...
}
有关在Perl中使用引用的介绍,请参见
do\u hash\u thing(%hash)
键
和其他哈希运算符sub do_hash_thing {
my %hash = @_;
...
}
do_hash_thing( %hash );
这还允许您“流化”散列参数:
do_hash_thing( %hash_1, %hash_2, parameter => 'green', other => 'pair' );
参考如下:
sub printInfo {
my %hash = @_;
...
}
sub do_hash_thing {
my $hash_ref = shift;
...
}
do_hash_thing( \%hash, @other_args );
这里使用prototype(\%@)
。prototype使perl在第一个参数中查找散列并通过引用传递它
sub do_hash_thing (\%@) {
my $hash_ref = shift;
...
}
do_hash_thing( %hash => qw(other args) );
# OR
do_hash_thing %hash => qw(other args);
警告:原型在方法上不起作用。传递散列和数组的最佳方式是通过。引用只是将复杂数据结构作为单个数据点进行讨论的一种方式,它可以存储在标量变量中(如
$foo
)
请继续阅读,以便您了解如何创建引用和取消引用,以便恢复原始数据
最基本的是:在数据结构前面加一个反斜杠以获得对该结构的引用
my $hash_ref = \%hash;
my $array_ref = \@array;
my $scalar_ref = \$scalar; #Legal, but doesn't do much for you...
sub mysub {
my $hash_ref = shift;
if ( ref $hash_ref ne "HASH" ) {
croak qq(You need to pass in a hash reference);
}
引用是原始结构的内存位置(加上有关该结构的线索):
将打印如下内容:
HASH(0x7f9b0a843708)
要将引用恢复为可用格式,只需将引用放在正确的前面:
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 };
您可以使用以下命令查看引用所指的内容:
如果希望确保传递的数据结构类型正确,则此选项非常有用
my $hash_ref = \%hash;
my $array_ref = \@array;
my $scalar_ref = \$scalar; #Legal, but doesn't do much for you...
sub mysub {
my $hash_ref = shift;
if ( ref $hash_ref ne "HASH" ) {
croak qq(You need to pass in a hash reference);
}
还要注意,这些是内存引用,因此修改引用将修改原始哈希:
my %hash = (this => 1, is => 2, a => 3 test => 4);
print "$hash{test}\n"; # Printing "4" as expected
sub mysub ( \%hash ); # Passing the reference
print "$hash{test}\n"; # This is printing "foo". See subroutine:
sub mysub {
my $hash_ref = shift;
$hash_ref->{test} = "foo"; This is modifying the original hash!
}
这可能是好的——它允许您修改传递给子例程的数据,也可能是坏的——它允许您无意中修改传递给原始子例程的数据。
&
通常是可选的,而且(通常)由于Perl生成默认参数的方式,使用它不是一种最佳实践,但它并没有被弃用。有时它是必需的,有时它不是必需的,但它仍然可以使代码更具可读性。先生,您在技术上是正确的:最好的一种正确。我已经澄清了我对此的评论。不是“而且可能更老”。在1993-05年2月的最后一个perl4版本4.036中,函数调用通常仍然需要&
。相信我,我也在场。☺ 避免这种情况的唯一方法是使用do mysubname()
语法-顺便说一句,它仍然可以很好地工作,这让少数偶然发现它的人感到惊讶。mob&subname
仍然用于定义的
和未定义的
参数,或`\\`或转到
运算符的操作数。对于调用,它用于规避原型检查。&foo()
对你的@
很好,而&foo
没有parens是隐藏的。goto&foo
对于尾部递归可能更清晰,除非你不能从这里开始。()
是偶数长度列表,(\%)
是散列引用。第二个选项是最好的方法。
printInfo(\%hash);
sub PrintInfo {
my %hash = %{$_[0]};
...
}