perl 中 hash 属性 访问的回调
Callback for hash property access in perl
Perl 中是否有任何本机方法可以知道访问了散列的哪个键?
某些语言中存在的魔术方法或代理对象之类的东西?
是的,有。它被称为 "tying" 变量。
tie
是实例化代理对象(来自指定的 class)并将其绑定到变量的组合。
详情见perldoc perltie
。
简短版本是:
tie %hash, 'Some::Class';
然后访问 %hash
将触发 Some::Class
中的方法调用(前提是它实现了 TIEHASH
构造函数和接口的其余部分)。
Perl 允许您 tie
一个变量到 class。这提供了一种机制,可以将您的自定义代码(绑定 class 的代码)注入到可以对绑定变量执行的各种操作中。对于散列,这些操作是 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";
在此示例中,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
也是 returns 一个不经常使用的对象,但可以用来提供额外的方法,这些方法可以针对不属于默认集合的散列调用上面列出的哈希操作。
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.
所以在这里我们调用了我们放在 SumHash
class 中的 sum
方法。 class 仍然继承自 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 的通用容器:标量、数组、散列或文件句柄。
有关使用 tie
的 Perl 文档中最详尽的解释可在 perldoc perltie
找到
Perl 中是否有任何本机方法可以知道访问了散列的哪个键?
某些语言中存在的魔术方法或代理对象之类的东西?
是的,有。它被称为 "tying" 变量。
tie
是实例化代理对象(来自指定的 class)并将其绑定到变量的组合。
详情见perldoc perltie
。
简短版本是:
tie %hash, 'Some::Class';
然后访问 %hash
将触发 Some::Class
中的方法调用(前提是它实现了 TIEHASH
构造函数和接口的其余部分)。
Perl 允许您 tie
一个变量到 class。这提供了一种机制,可以将您的自定义代码(绑定 class 的代码)注入到可以对绑定变量执行的各种操作中。对于散列,这些操作是 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";
在此示例中,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
也是 returns 一个不经常使用的对象,但可以用来提供额外的方法,这些方法可以针对不属于默认集合的散列调用上面列出的哈希操作。
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.
所以在这里我们调用了我们放在 SumHash
class 中的 sum
方法。 class 仍然继承自 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 的通用容器:标量、数组、散列或文件句柄。
有关使用 tie
的 Perl 文档中最详尽的解释可在 perldoc perltie