perl中哈希属性访问的回调

perl中哈希属性访问的回调,perl,perl-hash,Perl,Perl Hash,在Perl中有没有任何本机方法可以知道访问了散列的哪个键? 某些语言中存在的魔法方法或代理对象?是的,确实存在。这叫做“捆绑”变量 是实例化代理对象(来自指定类)并将其绑定到变量的组合 有关详细信息,请参阅 简短的版本是: tie %hash, 'Some::Class'; 然后访问%hash将触发Some::Class中的方法调用(前提是它实现了TIEHASH构造函数和接口的其余部分)。是的,有。这叫做“捆绑”变量 是实例化代理对象(来自指定类)并将其绑定到变量的组合 有关详细信息,请参阅

在Perl中有没有任何本机方法可以知道访问了散列的哪个键?

某些语言中存在的魔法方法或代理对象?

是的,确实存在。这叫做“捆绑”变量

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

有关详细信息,请参阅

简短的版本是:

tie %hash, 'Some::Class';

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

是的,有。这叫做“捆绑”变量

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

有关详细信息,请参阅

简短的版本是:

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

Perl允许您将变量添加到类中。这提供了一种机制,将自定义代码(绑定类的代码)注入到可以在绑定变量上执行的各种操作中。对于散列,这些操作是
TIEHASH
STORE
FIRSTKEY
FETCH
NEXTKEY
EXISTS
DELETE
CLEAR
,以及
SCALAR

因此,绑定哈希的完整实现将实现这些方法中的每一种。为了简化这一过程,核心Perl发行版提供了模块,该模块还提供了
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";
在本例中,
FETCH
STORE
方法被代码覆盖,导致它们向
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
的最详尽解释可在上找到。Perl允许您将变量添加到类中。这提供了一种机制,将自定义代码(绑定类的代码)注入到可以在绑定变量上执行的各种操作中。对于散列,这些操作是
TIEHASH
STORE
FIRSTKEY
FETCH
NEXTKEY
EXISTS
DELETE
CLEAR
,以及
SCALAR

因此,绑定哈希的完整实现将实现这些方法中的每一种。为了简化这一过程,核心Perl发行版提供了模块,该模块还提供了
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";
在本例中,
FETCH
STORE
方法被代码覆盖,导致它们向
STDERR
吐出一些诊断信息。然后,我们通过最后调用
SUPER::*
来保留这些方法的常规哈希语义。我们可以简单地实现我们自己的功能版本,而不是调用SUPER,但是利用现有的实现不太容易出错

输出f