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

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 仍用于definedundef 参数,或` \\ ` 或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);

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

【讨论】:

(%) 是偶数长度列表,(\%) 是哈希参考

以上是关于如何将哈希传递给子例程?的主要内容,如果未能解决你的问题,请参考以下文章

将 Word.Document 传递给子例程

如何将可分配数组传递给 Fortran 中的子例程

如何将 C_FLOAT 数组传递给 Fortran 子例程

无法通过从两个不同子例程传递给新子例程的值来执行计算:Perl

将指向 uint16_t 的指针传递给需要 C 中 uint8_t[] 数组的子例程 - 如何?

将两个或多个数组传递给 Perl 子例程