【问题标题】: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";
    }
}

【问题讨论】:

    标签: perl hash subroutine


    【解决方案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 "$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】:

      我相信你想要

      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】:

        您可以将它们传递为

        1. 参数列表do_hash_thing( %hash )
        2. 对参数列表中哈希的引用 `do_hash_thing(@args_before, \%hash, @args_after)
        3. 作为 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);
        

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

        【讨论】:

        • (%) 是偶数长度列表,(\%) 是哈希参考
        猜你喜欢
        • 2011-02-01
        • 1970-01-01
        • 2020-06-14
        • 1970-01-01
        • 2016-12-04
        • 2017-01-18
        • 2018-02-24
        • 1970-01-01
        相关资源
        最近更新 更多