有没有办法在Perl中使用"常量"作为哈希键?

时间:2020-03-06 14:23:27  来源:igfitidea点击:

有什么方法可以使用常量作为哈希键吗?

例如:

use constant X => 1;

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

上面的代码将创建一个以" X"为键而不是1为键的哈希。而我想使用常数X的值作为键。

解决方案

"使用常量"实际上使常量子例程。

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

use constant X => 1;

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

或者

use constant X => 1;

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

问题是=>是一个魔术逗号,它会自动在其前面加上单词。因此,我们编写的内容等同于('X','X')。

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

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

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

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

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

尝试使用

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

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

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

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

my %x ( X, 1 );

使用$ hash {CONSTANT()}或者$ hash {+ CONSTANT}可以防止裸字引号机制启动。

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

另一个选择是不使用Damian Conway的Perl Best Practices中的建议使用使用常量编译指示并将其翻转为Readonly。

在意识到常量哈希引用只是对哈希的常量引用之后,我又转回了一会儿,但是对哈希内部的数据不做任何事情。

只读语法会创建"外观正常"的变量,但实际上会强制执行恒定性或者只读性。我们可以像使用其他任何变量作为键一样使用它。

use Readonly;

Readonly my $CONSTANT => 'Some value';

$hash{$CONSTANT} = 1;

"使用常量"用法创建了一个子例程,原型不带任何参数。它看起来像C风格的常量,但实际上是一个返回常量值的子例程。

" =>"(胖逗号)会自动引用左操作数(如果是裸字),就像$ hash {key}表示法一样。

如果我们使用的常量名称看起来像一个简单的单词,则将引入引号机制,我们将获得其名称作为键而不是其值。为防止这种情况,请更改用法,以免成为空白。例如:

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

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

%hash = (X, 1);

其他大多数人都很好地回答了问题。综合起来,这些内容可以很好地解释问题并提供建议的解决方法。问题是Perl编译指示"使用常量"确实在当前包中创建了一个子例程,该例程的名称是编译指示的第一个参数,而值是最后一个。

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

了解"常量"只是子例程,我们可以了解为什么它们未插入字符串中,以及引用左手引数的"胖逗号"运算符" =>"为什么认为我们已将其交给了字符串(尝试其他-有时会用胖逗号添加time()和keys()之类的函数,以带来更多乐趣)。

幸运的是,我们可以使用显式标点(如parens或者&符)来调用常量。

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

我可以想到一些可能导致我们朝这个方向发展的情况:

  • 我们想控制哪些键可以在哈希中。
  • 我们想要抽象键的名称,以防以后更改

对于数字1,常量可能不会保存哈希。相反,可以考虑创建一个具有公共设置器和获取器的类,该填充器和填充器将填充仅对对象可见的哈希。这是一个非常不像Perl的解决方案,但是很容易做到。

对于2号,我仍然会大力提倡Class。如果通过定义明确的接口来控制对哈希的访问,则仅该类的实现者负责正确设置哈希键名称。在这种情况下,我完全不建议使用常量。

希望这对我们有所帮助,并感谢宝贵时间。

评论@shelfoo(声誉尚不足以直接在此处添加评论!)

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

但是,如果我们打算将PBP用作内部样式指南,请阅读PBP模块建议注释,它是一个有用的"勘误表"。