0

Perl 中是否有任何本地方法可以知道访问了哈希的哪个键?
诸如某些语言中存在的魔术方法或代理对象之类的东西?

4

2 回答 2

5

就在这里。这称为“绑定”变量。

tie是实例化代理对象(从指定的类)并将其绑定到变量的组合。

详情请参阅perldoc perltie

简短的版本是:

tie %hash, 'Some::Class';

然后访问%hash将触发方法调用Some::Class(前提是它实现了TIEHASH构造函数和接口的其余部分)。

于 2017-11-09T19:02:58.783 回答
1

Perl 允许你将tie一个变量传递给一个类。这提供了一种机制,可以将您的自定义代码(绑定类的代码)注入到可以对绑定变量执行的各种操作中。对于哈希,这些操作是TIEHASH, STORE, FIRSTKEY, FETCH, NEXTKEY, EXISTS, DELETE, CLEAR, 和SCALAR.

因此,绑定散列的完整实现将实现这些方法中的每一个。为了使这更容易,核心 Perl 发行版提供了模块Tie::Hash,它还提供了Tie::StdHash.

Tie::StdHash可能是将某些功能添加到其他相当典型的哈希实现的最短路径,因为它提供了上述每种哈希方法的标准实现。要添加您自己的功能,您可以重写那些有意义的方法。然后调用SUPER::*(其中 * 表示被覆盖操作的名称)或在被覆盖的方法中完整地提供所需的散列功能。一个例子可能比文字更简单:

package NoisyHash;

use strict;
use warnings;

require Tie::Hash;
our @ISA = q(Tie::StdHash);

sub STORE {
    my ($self, $key, $value) = @_;
    warn "\tSet $key to $value\n";
    return $self->SUPER::STORE($key, $value);
}

sub FETCH {
    my ($self, $key) = @_;
    warn "\tFetch from $key\n";
    return $self->SUPER::FETCH($key);
}

1;


package main;

use strict;
use warnings;

tie my %hash, 'NoisyHash';

$hash{A} = 1;
$hash{B} = 'foo';

print "\$hash{A} = $hash{A}\n";
print "\$hash{B} = $hash{B}\n";

在此示例中,FETCHandSTORE方法被代码覆盖,导致它们向STDERR. 然后我们通过最终调用来为这些方法保留常规哈希语义SUPER::*。我们可以简单地实现我们自己版本的该功能而不是调用 SUPER,但利用现有实现不太容易出错。

前面示例的输出是:

    Set A to 1
    Set B to foo
    Fetch from A
$hash{A} = 1
    Fetch from B
$hash{B} = foo

如示例所示,该tie函数用于绑定NoisyHash%hash. 事实证明,tie它还返回一个不经常使用的对象,但可用于提供可以针对不属于上面列出的默认散列操作集的散列调用的其他方法。

package SumHash;

use strict;
use warnings;

require Tie::Hash;
our @ISA = q(Tie::StdHash);
use List::Util;

sub sum {
    my $self = shift;
    return List::Util::sum(values %$self);
}

1;

package main;

use strict;
use warnings;

my $hash_obj = tie my %hash, 'SumHash';

@hash{qw(a b c d e)} = (1, 2, 3, 4, 5);

my $sum = $hash_obj->sum;
print "Sum of (",
      join(', ', values %hash),
      ") is $sum.\n",

此代码的示例输出为:

Sum of (3, 4, 1, 5, 2) is 15.

所以这里我们调用了一个sum放在SumHash类中的方法。该类仍然继承自Tie::StdHash,并且不覆盖任何标准方法,因此它仍然保留标准哈希功能。但它确实增加了计算哈希值的能力。但是,这不是计算哈希值的最简单方法。与其费力地绑定一个散列来添加总和,不如这样做:

use List::Util qw(sum);
print "Sum of (", join(', ', values %hash), ") is ", sum(values %hash), "\n";

这说明了为什么 Perl 社区普遍认为绑定变量很少是解决典型问题的最佳方法。捆绑变量会让人难以理解和推理远距离的行动。绑定变量的性能要差得多。但是这种做法偶尔也有正当的用途,Perl 提供了一种方法。

有关perldoc Tie::Hash该模块的说明,请参阅 。请注意,它tie可用于绑定 Perl 的任何常用容器:标量、数组、散列或文件句柄。

Perl 文档中最详尽的使用说明tie可在以下位置获得perldoc perltie

于 2017-11-10T02:18:27.450 回答