32

有没有办法使用常量作为哈希键?

例如:

use constant X => 1;

my %x = (X => 'X');

上面的代码将创建一个以“X”作为键而不是 1 作为键的散列。然而,我想使用常量 X 的值作为键。

4

9 回答 9

49

use constant实际上制作了常量子程序。

要执行您想要的操作,您需要显式调用 sub:

use constant X => 1;

my %x = ( &X => 'X');

或者

use constant X => 1;

my %x = ( X() => 'X');
于 2008-09-18T20:57:00.840 回答
19

另一种选择是不使用 use constant pragma 并按照 Damian Conway 的 Perl Best Practices 中的建议翻转到 Readonly。

在意识到常量哈希引用只是对哈希的常量引用后,我切换了一段时间,但不对哈希内的数据做任何事情。

readonly 语法会创建“正常外观”的变量,但实际上会强制保持不变性或只读性。您可以像使用任何其他变量一样使用它作为键。


use Readonly;

Readonly my $CONSTANT => 'Some value';

$hash{$CONSTANT} = 1;

于 2008-09-18T21:11:07.547 回答
15

您的问题是 => 是一个神奇的逗号,它会自动引用它前面的单词。所以你写的相当于('X','X')。

最简单的方法是只使用逗号:

my %x = (X, 'X');

或者,您可以添加各种标点符号,以便在 => 前面不再有一个简单的单词:

my %x = ( X() => 'X' );
my %x = ( &X => 'X' );
于 2008-09-18T20:57:32.650 回答
10

使用$hash{CONSTANT()}$hash{+CONSTANT}防止裸词引用机制启动。

来自: http: //perldoc.perl.org/constant.html

于 2008-09-18T21:00:09.243 回答
6

大多数其他人都很好地回答了你的问题。总而言之,这些内容对问题和推荐的解决方法提供了非常完整的解释。问题是 Perl 编译指示“使用常量”确实在您当前的包中创建了一个子例程,其名称是编译指示的第一个参数,其值是最后一个。

在 Perl 中,一旦声明了子例程,就可以在没有括号的情况下调用它。

理解“常量”只是子例程,您可以看到为什么它们没有插入到字符串中,以及为什么引用左侧参数的“胖逗号”运算符“=>”认为你已经给它一个字符串(尝试其他内置-in 函数,如 time() 和 keys() 有时会加上逗号以获得​​额外的乐趣)。

幸运的是,您可以使用显式标点符号(如括号或 & 符号)来调用常量。

但是,我有一个问题要问您:您为什么要使用常量作为哈希键?

我可以想到一些可能会引导您朝这个方向发展的场景:

  1. 您想要控制哪些键可以在散列中。

  2. 您想抽象键的名称以防以后更改

在数字 1 的情况下,常量可能不会保存您的哈希值。相反,请考虑创建一个具有公共 setter 和 getter 的类,它们填充仅对对象可见的散列。这是一个非常不像 Perl 的解决方案,但很容易做到。

就第 2 种情况而言,我仍然强烈主张建立一个班级。如果对哈希的访问是通过定义良好的接口进行管理的,那么只有类的实现者负责正确获取哈希键名。在这种情况下,我根本不建议使用常量。

希望这会有所帮助,并感谢您的宝贵时间。

于 2008-09-18T22:00:14.917 回答
5

pragma 创建了一个子例程原型,use constant不接受任何参数。虽然它看起来像一个 C 风格的常量,但它实际上是一个返回常量值的子例程。

如果=>(fat comma) 是裸字,则 (fat comma) 会自动引用左操作数,$hash{key} 表示法也是如此。

如果您对常量名称的使用看起来像一个裸词,那么引用机制将启动,您将获得它的名称作为键而不是它的值。为防止这种情况发生,请更改用法,使其不是裸词。例如:

use constant X => 1;
%hash = (X() => 1);
%hash = (+X => 1);
$hash{X()} = 1;
$hash{+X} = 1;

在初始化程序中,您也可以使用普通逗号代替:

%hash = (X, 1);
于 2008-09-18T21:16:26.287 回答
2

=> 运算符将其左侧解释为“字符串”,就像 qw() 一样。

尝试使用

my %x = ( X, 'X');
于 2008-09-18T20:58:17.187 回答
2

一种方法是将 X 封装为 (X):

my %x ( (X) => 1 );

另一种选择是取消 '=>' 并使用 ',' 代替:

my %x ( X, 1 );
于 2008-09-18T20:58:25.127 回答
1

评论@shelfoo(声誉还不够高,无法直接在那里添加评论!)

完全同意 Damian Conway 的 Perl Best Practices ……强烈推荐阅读。

但是,如果您打算将 PBP 用作内部风格指南,请阅读PBP 模块推荐评论,这是一个有用的“勘误表”。

于 2008-09-22T11:33:06.987 回答