【问题标题】:passing a hash to a subroutine(s)将哈希传递给子程序
【发布时间】:2020-06-14 06:38:53
【问题描述】:

我正在为自己开发一个项目,但在将哈希传递给子例程时遇到了问题。实际上有几个子例程,但我试图将其精简到最低限度。我意识到 %mdc 是一个全局哈希,所以我不必将它传递给我拥有的所有子例程,但出于习惯,我更喜欢这种方式。虽然下面的 sn-p 确实有效,但感觉它可以更清洁。

不管怎样,让我想到一定有更好的方法的部分是以下几行:

%mdc_def = mysub(\%mdc);
%mdc = %$mdc_def;

感觉...对我来说很笨拙,但我没有找到一种方法让这两行只是一个...类似于(即使它的语法不好):

%mdc = %mysub(\%mdc);

然后,如果我应该有一个 mysub2 也需要该哈希,那么我也必须在该子例程中执行相同的两行随机播放。只是感觉很乱。

这是我正在处理的 sn-p:

use strict;
use warnings;

my %mdc = ();
my $mdc_def;

$mdc{abc} = 123;
$mdc{cde} = 234;

foreach (sort keys (%mdc)) { print "before $_ = $mdc{$_}\n"; }
$mdc_def = mysub(\%mdc);
%mdc = %$mdc_def;
foreach (sort keys (%mdc)) { print " after $_ = $mdc{$_}\n"; }

sub mysub {
  my ($mdc_def) = @_;
  my %m = %$mdc_def;

  $m{def} = 345;
  $m{efg} = 456; 

  return \%m;
}

提前致谢。

【问题讨论】:

    标签: perl hash subroutine


    【解决方案1】:

    您可以使用以下内容:

    sub mysub {
       my ($mdc_def) = @_;
       my %m = %$mdc_def;
    
       $m{def} = 345;
       $m{efg} = 456; 
    
       return \%m;
    }
    
    my %mdc = ( a=>1, b=>2 );
    
    %mdc = %{ mysub(\%mdc) };
    

    但这不会产生散列和其中所有标量的一个两个副本。全局 var 没有理由成为散列而不是标量,这样可以避免复制实例之一。

    sub mysub {
       my ($mdc_def) = @_;
       my %m = %$mdc_def;
    
       $m{def} = 345;
       $m{efg} = 456; 
    
       return \%m;
    }
    
    my $mdc = { a=>1, b=>2 };
    
    $mdc = mysub(\%mdc);
    

    剩下一个复制实例。如果您不希望 mysub 就地修改哈希值,则需要该实例,因此上面的代码很好。

    以下版本会就地修改哈希,避免第二次复制(并允许我们将全局变量保留为哈希)。

    sub mysub_inplace {
       my ($mdc_def) = @_;
       $mdc_def->{def} = 345;
       $mdc_def->{efg} = 456; 
    }
    
    my %mdc = ( a=>1, b=>2 );
    
    mysub_inplace(\%mdc);
    

    【讨论】:

      【解决方案2】:

      试试

      %mdc = %{mysub(\%mdc)};
      
      • \%mdc 将对%mdc 哈希的引用作为参数传递给mysub suroutine
      • %{ mysub(…)} 会将mysub 调用的返回值视为哈希引用并将其转换为哈希

      您可以使用子程序原型sub mysub (\%) 调用mysub 和mysub(%mdc)


      简单的工作示例/脚本:

      #!/usr/bin/perl
      # Original version constained prototypes for sub mysub - 
      # see ikegami comments below the answear
      use strict;
      use warnings;
      
      sub mysub {
        my( $hRef ) = (@_);
        $hRef->{a} = 0;
        $hRef->{c} = 3;
        return $hRef;
      }
      
      my %mdc = ( a=>1, b=>2);
      
      %mdc = %{mysub(\%mdc)};
      print %mdc;
      

      【讨论】:

      • 请避免使用原型。它们造成的问题比什么都多。
      • @ikegami 你能更具体一点吗? [链接!] 我很少在我的小脚本中使用它们,但在更大的脚本中它们似乎是个好主意。
      • 大部分人使用它们来验证,但实际上它们改变了解析规则。您无缘无故地使用了一个使潜艇变得神奇。根据定义,不必要的魔法是不好的。代码在做另一件事时不应该看起来像是在做一件事,尤其是无缘无故的。例如如果你想要一个特定的例子,%foo 通常不会在f(%foo) 中被更改,因为这通常会传递键和值。但是您使用的原型改变了这一点。突然间,f 能够改变%foo
      • 简而言之,惊喜是不好的,原型会带来惊喜。 (& 是一个例外。)他们被广泛回避。
      • 哦,那是假设它们甚至可以工作。大多数时候,它们甚至都不工作。它们不适用于方法调用,并且当通过引用调用 sub 时它们也不起作用。如果您以错误的顺序放置代码,它们也不起作用。您可以对 sub 进行两次相同的调用,并且只有其中一个有效。真是一团糟。
      【解决方案3】:

      您了解$hash_ref = \%hash 是什么以及如何使用它吗?

      use strict;
      use warnings;
      use feature 'say';
      
      my %mdc = ();
      
      $mdc{abc} = 123;
      $mdc{cde} = 234;
      
      say '- Before ------------';
      
      while( my($k,$v) = each %mdc ) {
          say "$k => $v";
      }
      
      mysub(\%mdc);
      
      say '- After -------------';
      
      while( my($k,$v) = each %mdc ) {
          say "$k => $v";
      }
      
      sub mysub {
        my $mdc_ref = shift;
      
        $mdc_ref->{def} = 345;
        $mdc_ref->{efg} = 456; 
      }
      

      输出

      - Before ------------
      cde => 234
      abc => 123
      - After -------------
      def => 345
      cde => 234
      abc => 123
      efg => 456
      

      【讨论】:

        猜你喜欢
        • 2011-06-21
        • 1970-01-01
        • 2011-02-01
        • 2013-03-11
        • 2013-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多