如何将哈希传递给子例程?

时间:2011-02-03 23:51:29

标签: 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 (%hash) = %_;
   foreach my $key (keys %_{       
    my $a = $_{$key}{'Make'};   
    my $b = $_{$key}{'Color'};   
    print "$a $b\n";
    }
}

5 个答案:

答案 0 :(得分:33)

简单的方法,可能会在代码发展时导致问题,只需将默认数组@_(包含所有键值对作为偶数列表)分配给%hash,然后根据其重建。所以你的代码看起来像这样:

sub printInfo {
   my %hash = @_;
   ...
}

更好的方法是将哈希作为对子例程的引用传递。这样,您仍然可以将更多参数传递给子例程。

printInfo(\%hash);
sub PrintInfo {
   my %hash = %{$_[0]};
   ...
}

可以在perlreftut

中找到在Perl中使用引用的简介

答案 1 :(得分:8)

你非常非常接近。传递哈希值没有%_,必须在@_中传递。幸运的是,Hashes是使用列表上下文分配的,所以

sub printInfo {
   my %hash = @_;
   ...
}

会让它发挥作用!

另请注意,在大多数情况下,使用子程序调用前面的&至少不需要Perl 5.000。这些天你可以像其他语言一样调用Perl子程序,只需要名称和参数。 (正如@mob在评论中指出的那样,有些情况下仍然需要这样做;如果感兴趣,请参阅perlsub以了解更多信息。)

答案 2 :(得分:6)

我相信你想要

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,它会再次创建带有列表中交替元素的相应值的键。

答案 3 :(得分:5)

传递哈希和数组的最佳方法是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);
    }

另请注意,这些是内存引用,因此修改引用将修改原始哈希:

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!
}

这可能很好 - 它允许您修改传递给子例程的数据,或者坏 - 它允许您无意中修改传递给原始子例程的数据。

答案 4 :(得分:3)

您可以将其作为

传递
  1. 参数列表do_hash_thing( %hash )
  2. 对参数列表中的哈希的引用 `do_hash_thing(@ args_before,\%hash,@ args_after)
  3. 作为 prototype 的参考,像keys和其他哈希运算符一样工作。
  4. 列表的工作原理如下:

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

    警告:原型不适用于方法。