【问题标题】:Using Constants in Perl在 Perl 中使用常量
【发布时间】:2010-06-16 20:44:15
【问题描述】:

我正在尝试使用constant pragma 在 Perl 中定义常量:

use constant {
    FOO => "bar",
    BAR => "foo"
};

我遇到了一些麻烦,希望有一个标准的方法来处理它。

首先...

我正在为 Subversion 定义一个钩子脚本。为简单起见,我想要一个文件,其中我使用的类(包)与我的实际脚本在同一个文件中。

这个包的大部分内容都会涉及到常量:

 print "This is my program";

 package MyClass;

 use constant {
    FOO => "bar"
 };

 sub new { ... }

我希望我的主程序可以访问我的常量 FOO。我想这样做而不必将其称为MyClass::FOO。通常,当包是一个单独的文件时,我可以在我的主程序中这样做:

use MyClass qw(FOO);

但是,由于我的课程和程序是一个文件,我不能这样做。让我的主程序能够访问我的类中定义的常量的最佳方式是什么?

第二期……

我想使用常量值作为哈希键:

$myHash{FOO} = "bar";

问题在于%myHash 将文字字符串FOO 作为键而不是常量的值。当我做这样的事情时,这会导致问题:

if (defined $myHash{FOO}) {
   print "Key " . FOO . " does exist!\n";
}

我可以强制上下文:

if (defined $myHash{"" . FOO . ""}) {

我可以加括号:

if (defined $myHash{FOO()}) {

或者,我可以使用临时变量:

my $foo = FOO;
if (defined $myHash{$foo}) {

这些都不是处理这个问题的好方法。那么,最好的方法是什么?我错过了一种方法吗?

顺便说一句,我不想​​使用Readonly::Scalar,因为它是 1)。慢,和2)。不是标准 Perl 包的一部分。我想定义我的钩子不需要额外的 Perl 包并且尽可能简单地工作。

【问题讨论】:

    标签: perl constants


    【解决方案1】:

    如果您想将所有内容保存在同一个文件中,您可以按如下方式定义常量包:

    use warnings;
    use strict;
    
    BEGIN {  # BEGIN means this will all happen at compile time
        package Constants;
    
        $INC{'Constants.pm'}++;     # tell `require` that the package is loaded
        use base 'Exporter';        # setup package to export
        our @EXPORT_OK = qw( PI );  # what to export
    
        use constant PI => 3.14159; # define your constant
    }
    
    package main;
    
    use Constants qw( PI );  # use it like normal
    
    print PI;
    

    然后为了欺骗哈希下标内的自动引用,你可以这样写:$hash{+PI}$hash{(PI)}$hash{PI()}$hash{&PI}$hash{::PI} ...我可能会继续,但是我认为你说对了。

    之所以需要$INC{'Constants.pm'}++,是因为use Constants qw( PI );这一行真正的意思是:

    BEGIN {
        require 'Constants.pm';
        Constants->import( qw( PI ) );
    }
    

    require 将检查%INC 以查看包是否已经加载。因此,通过给它一个真值(在这种情况下为 1),userequire 'Constants.pm'; 部分将变为无操作。

    【讨论】:

    • 没有考虑修改 $INC 数组。那会奏效的。谢谢!
    • @David W. => 很高兴帮助并欢迎 SO。另外,您知道use constant PI => 3.14159sub PI {3.14159} 的含义相同,我通常使用后者,因为它更短一些,并且不会误导人们认为它不是潜艇。
    • 请注意,如果您不想与%INC 混淆,您可以使用BEGIN { MyClass->import(qw(FOO)) } 而不是use MyClass qw(FOO);(在将MyClass 设置为以通常的方式使用Exporter 之后)。
    • 其实和sub PI () { 3.14159 }一样(注意空原型)。
    • 我知道这真的很老了,但是 Constants.pm 必须导出任何东西才能工作吗?
    【解决方案2】:
    1. Perl constants 不是常量。它们被编译定义为在编译时内联的特定类型的函数。

    2. 我发现 Perl 的“常量”使用起来比不使用更痛苦。所以,通常我的方法是使用全大写的标量。 my $PI = 3.14159;

    【讨论】:

    • 你应该将这些标量设为只读,否则有一天你会想知道为什么你的圆圈是方形的。
    • @Ether:正方形是圆的数字化近似值——只是分辨率不高。 :)
    • 如果我有足够的声誉,我会投反对票。良好的编程习惯需要使用常量。如果您不喜欢“使用常量”编译指示,请使用“只读”模块,或者使用老式的 typeglob 方式:*FOO = \"bar";我们的$FOO; print "FOO 的值为 $FOO\n"; #就像一个标量变量 $FOO = "barfoo"; #不能这样做! Readonly 不是标准模块,可能很慢。 Typeglobbing 很快,但语法很奇怪。
    • @David:是的,perl 中的常量有点坏了。所以我做有纪律的编程来处理这个问题。
    • @dolmen 不幸的是,Readonly 1 有两个问题。它不是标准 Perl 包的一部分。因此,我必须依赖站点来下载和安装,这可能并不总是可行的。 2. 它很慢——尤其是如果你不使用 XL 包的话。否则,与use Constant 相比,我更喜欢 Readonly 的工作方式。事实上,在很长一段时间里,我更喜欢 typeglobbing:*PI = \3.1415926;我们的$PI;这将允许我将常量视为变量,但我仍然无法修改它们。不幸的是,Perl 社区选择了Use Constant
    【解决方案3】:

    当它们出现在哈希查找中时,它们会被自动引用。您需要强制调用实现常量的 sub:

    $myHash{FOO}   = 'bar'; # doesn't work, bareword quoted
    $myHash{+FOO}  = 'bar'; # okay
    $myHash{&FOO}  = 'bar'; # okay
    $myHash{FOO()} = 'bar'; # okay
    

    将函数和变量从一个包导出到另一个包都是符号表操作。 Exporter 模块让我们很容易做到这一点,但没有模块也不难做到。

    package main;
    sub stuff { return &FOO x 3 }
    *FOO = *MyClass::FOO;
    print stuff();               # "barbarbar"
    
    package MyClass;
    use constant FOO => "bar";
    

    你也可以说

    BEGIN { *main::FOO = *FOO }
    

    package MyClass下。

    【讨论】:

    • 注意:为了让strict 'subs'开心,必须将全局分配包装在BEGIN块中。
    • 感谢您的回答。是的,我发现了看起来最好的酉运算符 (+)。我没有考虑符号表的修改。那会奏效的。如果我有足够的声誉,我会投票赞成这个答案。
    【解决方案4】:

    我第二个 Eric Strom 回答。

    但是,这里有另一种方式(但暴露了太多 Perl 实现):

    use strict;
    use warnings;
    
    package Constants;
    sub FOO() { 'bar' }
    sub BAR() { 'foo' }
    sub main::FOO() { FOO }
    sub main::BAR() { BAR }
    
    package main;
    
    print FOO, BAR, "\n";
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      相关资源
      最近更新 更多