似乎 Perl 只能将字符串作为哈希的键。(这在某个版本的 Perl 中是否已更改?)只能使用字符串作为键是非常有限的。如果我想要一个对象或数组作为键怎么办?在 Python 中,很容易使用数组、元组和其他可以比较的对象作为 dict 键。Perl 确实有能力比较诸如数组之类的东西是否相等,所以我不明白为什么它们不能用作映射类型的键。
没有办法在 Perl 中使用任何键类型吗?有没有提供这个的模块?
似乎 Perl 只能将字符串作为哈希的键。(这在某个版本的 Perl 中是否已更改?)只能使用字符串作为键是非常有限的。如果我想要一个对象或数组作为键怎么办?在 Python 中,很容易使用数组、元组和其他可以比较的对象作为 dict 键。Perl 确实有能力比较诸如数组之类的东西是否相等,所以我不明白为什么它们不能用作映射类型的键。
没有办法在 Perl 中使用任何键类型吗?有没有提供这个的模块?
是的,CPAN 上有这个模块:Tie::Hash::StructKeyed。它考虑了整个结构,但作为一个快照。each/keys 将返回原始参考。
AFAIK Perl 只是对键进行字符串化?
package Foo;
use Moose;
use overload ('""' => \&stringify);
sub stringify {
return "xxx";
}
package main;
use v5.10;
use Data::Dump 'pp';
my $foo = Foo->new;
my $hash = {$foo => 'bar'};
say pp($hash); // { xxx => "bar" }
这样你也可以使用任何你想要的作为哈希键。另请参阅Perl Monks 上的此线程。
至于相等,请看一下perlop 中的相等运算符。==
运算符按数字进行比较,运算eq
符按字符串进行比较。这意味着 example(4, 2) == (1, 2)
是 true (as scalar (4, 2)
is 2
),这可能会让您感到惊讶。
与您所说的相反,Perl 无法像您声称的那样比较诸如数组之类的东西是否相等。对于初学者,Perl 没有数组相等的定义。如果定义需要比较数组的内容,那么 Perl 也没有对可以在数组中找到的大多数事物进行相等定义。
Perl 对相等数组的定义最接近的是它们的地址。如果这就是你想要使用的,那么它很容易:
$key = ['a', 'b'];
$hash{$key} = [ $key, $val ]; # Prevents the key from being freed.
print $hash{$key}[1];
否则,Perl 让你自己实现你想要的,而不是强迫你使用它提供的东西。我看到两种主要方法。
绑定散列,基本上是呈现散列接口而不实际是散列表的代码,可以支持任何键类型。您可以使用它来定义您的数组相等版本。甚至可能有一个现有的模块(尽管在快速搜索后我没有看到一个)。
另一种方法是创建一个从键表达式生成唯一键的函数。
sub key{ "@_" } # Overly simplistic?
$hash{key('a', 'b')} = $val;
print $hash{key('a', 'b')};
是的,使用字段哈希(Hash::Util::FieldHash用于 5.10+ 和Hash::Util::FieldHash::Compat用于 5.10 之前)将您的哈希注册为字段哈希,您可以使用任何参考(因此,任何对象)作为这些散列的键(它本质上使引用数字化,并提供处理跨线程克隆和垃圾收集键的逻辑),例如:
use Hash::Util qw/fieldhashes/;
fieldhashes \my (%foo, %bar, %baz);
my %data = (a => 1, b => 2, c => 3);
my $stuff = {t => 2, u => 3, l => 9};
$foo{\%data} = 'x';
$foo{$stuff} = 'a';
$bar{\%data} = 'y';
$bar{$stuff} = 'b';
$baz{\%data} = 'z';
$baz{$stuff} = 'c';
print "$foo{\%data} $bar{\%data} $baz{\%data}\n";
print "$foo{$stuff} $bar{$stuff} $baz{$stuff}\n";