【问题标题】:How do I dereference a hash that's been returned from a method of a class?如何取消引用从类的方法返回的哈希?
【发布时间】:2011-01-16 08:30:06
【问题描述】:

我有一个类,它有一个返回哈希的方法。通常,我会得到这样的结果:

%resp = $myclass->sub($foo);

然后像这样访问返回的哈希的成员:

$resp{key}{subkey};

在二维散列的情况下。

我认为必须有一种方法可以将其组合成一条优雅的线条,如下所示:

$myclass->sub($foo)->{key}{subkey}

这显然没有正确解引用,因为 Perl 在尝试运行代码时会返回这个:

不能使用字符串 ("1/8") 作为 HASH ref

在尝试随机解引用序列时,通过查看 "References quick reference" on Perlmonks,我想出了以下内容,Perl 没有抱怨,但也没有返回我正在寻找的内容:

$%{$myclass->sub($foo)}->{key}{subkey}

谁能告诉我解除引用转义序列的神奇之处是什么?

【问题讨论】:

  • 每个人似乎都想通过将两条完美的线路变成一条混乱的线路来让那里的生活更艰难。当然还有更好的事情要考虑。 :)

标签: perl class hash dereference


【解决方案1】:

您尝试做的既不优雅也不可取。您以某种方式设法在标量上下文中调用例程(这就是 "1/8" 对应的内容)。

返回一个哈希引用。

现在,看看:

#!/usr/bin/perl

package My::Mine;

use strict; use warnings;

sub test {
    my %h = (
        a => { z => 1},
        b => { y => 2},
    );
    return %h;
}

package main;

use strict; use warnings;

my $class = 'My::Mine';

print { $class->test }->{a}{z}, "\n";

那是行不通的。相反,您必须这样做:

print +{ $class->test }->{a}{z}, "\n";

现在,这很优雅(不是!)请参阅perldoc -f print

长话短说,返回对哈希的引用。

请注意,您正在构建的新匿名哈希不是免费的。从子例程返回散列作为平面列表的成本也不是。

【讨论】:

  • 我不明白 + 在这里的用途。我很欣赏教育。谢谢。
  • +1 用于清楚地解释 1/8。此外,返回哈希还有一个缺点——如果你认为“这是一个副本,所以我可以安全地修改它”,它会让你产生一种错误的安全感——然而,数据结构的内部仍然是不是深度克隆,因此您无法安全地修改它们。
  • + 是对解析器的提示,即 print 后面的 {...} 构造不是 print 方法的间接对象。这用于print {sub_returns_a_file_handle()} "stuff to print - note that there is not a comma before the open quote";等情况
【解决方案2】:

更改 sub 以返回哈希引用效果最好,但要获得您正在寻找的功能:

{ $myclass->sub($foo) }->{key}{subkey}

这将从sub返回的列表中创建一个哈希引用,然后立即取消引用它

编辑:从您的 sub 返回 hashref 而不是 hash(作为列表)的优势主要是性能之一。在 hashref 的情况下,哈希被创建一次,然后被访问。在列表情况下,哈希被创建,然后转换为列表,然后再次创建,然后被取消引用。对于小散列,这不会花费太多时间,但对于较大的散列,这只是运行时不必要的工作。基本上,如果您打算在某些地方将数据用作列表,而在其他地方用作哈希,则可以将哈希作为列表返回。但是,如果您一直计划将其用作哈希,则返回引用会更清晰、更快。

【讨论】:

  • 这让我得到了我正在寻找的东西,同时维护了我现有的类代码。谢谢!
【解决方案3】:

我会改为从 sub 返回 HASH 引用。否则(可能)您的哈希会无缘无故地变成 LIST 然后再次变成 HASH:

sub mysub() {
  ...
  return \%myhash;
}

返回引用时涉及的复制更少,因此效率更高。

【讨论】:

  • 哈希变成了一个列表,而不是一个数组。区别很微妙但很重要。
  • 我可以做到。你能解释一下返回 hashref 而不是 hash 的好处吗?我可以很容易地修改课堂上的其他方法。谢谢!
  • 谢谢埃里克。我本来打算写 LIST 但已经有一段时间了。我的 Perl 现在已经生锈了。
  • 没有。只要它们被引用,您的引用对象就会存在。但是请确保不要创建循环引用,因为 Perl 的 GC 通过引用计数来工作。
  • 一旦hashref被返回,一个对它的引用就存在于调用范围内,它保留了这个值。 Perl 使用基于引用计数的垃圾回收系统,因此只要对值的引用存在,就不会被清理。一旦返回值超出范围(如果它没有被复制到其他任何地方),那么 Perl 将释放内存
【解决方案4】:

只返回一个 hashref 而不是一个 hash:

$myclass->sub($foo)->{key}->{subkey}

【讨论】:

  • 与 {key} 之前的 -> 的结果相同。谢谢。
  • 如果我取出 -> 完全一样的结果。
  • 不是我。我现在正在全力以赴,没有得分。
【解决方案5】:

如果您总是只想获得一个子密钥,请编写一个简短的子例程来为您执行此操作,而不必担心打高尔夫球。一个优点是您可以轻松添加一些健全性检查:

 sub get_subkey {
      my( $class, $arg, $key, $subkey ) = @_;

      my $hashref = $class->method( $arg );
      return unless ref $hashref;

      return $hashref->{$key}{$subkey};
      }

【讨论】:

    猜你喜欢
    • 2014-05-08
    • 2011-07-30
    • 2011-12-13
    • 2012-05-28
    • 1970-01-01
    • 2011-02-27
    • 2011-10-11
    • 2021-02-03
    • 1970-01-01
    相关资源
    最近更新 更多