【问题标题】:dereferencing hash without creating a local copy在不创建本地副本的情况下取消引用哈希
【发布时间】:2011-02-27 16:31:05
【问题描述】:

下面第 9 行的代码创建了哈希的本地副本。对 %d 的任何更改都不会提供对全局 %h 变量的更改(第 5 行)。我必须使用参考(第 8 行)来提供对 %h 的更改。

有没有办法在不创建本地副本的情况下取消引用 sub 中的哈希? 我在问,因为我有许多引用的复杂记录,并且通过取消引用在它周围导航会容易得多。

  1 #!/usr/bin/perl -w
  2 use strict;
  3 use warnings;
  4 
  5 my %h;
  6 sub a {
  7 
  8     my $href = shift;
  9     my(%d) = %{$href};   # this will make a copy of global %h
 10     
 11     $$href{1}=2;     # this will make a change in global %h
 12     $d{2}=2;         # this will not a change in global %h
 13 }   
 14 a(\%h);
 15 print scalar (keys %h) . "\n";

----------------

感谢您的回复。

问题是我可以在 sub 中对 %h 进行某种“别名/绑定”吗? 我想用 %d 更改子中 %h 的上下文。 每当我创建 %d 时,他都会制作 %h 的本地副本 - 有什么办法可以避免这种情况,还是我必须一直使用引用?

----------------

再来一次 :) 我知道 $href 是如何工作的。我阅读教程/手册/文档等。 我没有在那里找到答案 - 我认为这是不可能的,因为它没有写在那里,但谁知道呢。

我想完成这样的行为:

  6 sub a {
  7     $h{"1"}=2;
  8 }

相当于:

  6 sub a {
  8      my $href = shift;
  11     $$href{1}=2;     # this will make a change in global %h
  11     $href->{1}=2;    # this will make a change in global %h

现在如何在 %d 的帮助下做到这一点 - 真的有可能吗?

6 sub a {
7        my %d = XXXXXXXXX
.. }

在不创建本地副本的情况下,我应该在 XXXXXXXXX 下放置什么来指向 %h?

【问题讨论】:

  • 出于好奇——您列出的两种方法(使用 $$ 和箭头运算符的内联取消引用)有什么问题?
  • $$ 没问题。我只是好奇。

标签: perl hash dereference


【解决方案1】:

使用哈希引用的两种方式:

  1. 你自己正在使用的一个

    $$href{'key2'} = "key2";
    
  2. 上面指出:

    $href->{'key1'} = "key1";
    

http://perldoc.perl.org/perlreftut.html

【讨论】:

    【解决方案2】:

    要创建该值的本地别名,您需要使用 Perl 的包变量,可以使用 typeglob 语法为其命名(和local 来限定别名):

    #!/usr/bin/perl -w
    use strict;
    use warnings;
    
    my %h;
    
    sub a {
        my $href = shift;
    
        our %alias; # create the package variable (for strict)
    
        local *alias = $href;
            # here we tell perl to install the hashref into the typeglob 'alias'
            # perl will automatically put the hashref into the HASH slot of
            # the glob which makes %alias refer to the passed in hash.
            # local is used to limit the change to the current dynamic scope.
            # effectively it is doing:  *{alias}{HASH} = $href
    
        $$href{1}=2;     # this will make a change in global %h
        $alias{2}=2;     # this will also make a change in global %h
    }
    a(\%h);
    print scalar (keys %h) . "\n";  # prints 2
    

    这是一种相当先进的技术,因此请务必阅读 localtypeglobs 上的 Perl 文档,以便准确了解发生了什么(特别是在local 也将在范围内包含 %alias,因为 local 表示动态范围。本地化将在 a 返回时结束。)

    如果您可以安装Data::AliasCPAN 中的其他别名模块之一,则可以避免包变量并创建词法别名。上面的方法是唯一不需要额外模块的方法。

    【讨论】:

    • 同意,除非有非常好的理由使用别名,否则最好避免使用别名。我很好奇为什么 OP 拒绝仅使用参考。
    【解决方案3】:

    以下代码显示了如何使用箭头运算符取消引用(是的,不创建局部变量)

    阅读 this 了解有关取消引用和可能的不同类型的取消引用的教程。

    use warnings;
    use Data::Dumper::Simple;
    
    my %h;
    sub a {
        my $href = shift;
    
        #dereference using the arrow operator - *preferred*
        $href->{name} = "John"; 
    
    }
    
    a(\%h); #Passing the reference of the hash
    print Dumper(%h);
    

    为什么首先需要将全局哈希作为参数传递给子例程?

    1. 避免使用全局变量。
    2. 最好不要在任何变量被赋值后更改它们的状态。

    【讨论】:

      【解决方案4】:

      这对你有帮助吗

      $href->{1} = 2;
      print scalars (keys %{$href});
      

      ?

      【讨论】:

        猜你喜欢
        • 2017-12-28
        • 1970-01-01
        • 2019-05-12
        • 2021-01-16
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-25
        相关资源
        最近更新 更多