代码之家  ›  专栏  ›  技术社区  ›  David W.

在Perl中使用常量

  •  13
  • David W.  · 技术社区  · 14 年前

    我尝试使用 constant 语用学:

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

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

    首先…

    我正在为颠覆定义一个钩子脚本。为了简单起见,我希望有一个单独的文件,其中我使用的类(包)与实际脚本位于同一个文件中。

    这个包中的大多数都包含常量:

     print "This is my program";
    
     package MyClass;
    
     use constant {
        FOO => "bar"
     };
    
     sub new { ... }
    

    我想要我的常量 FOO 以访问我的主程序。我不想把它称为 MyClass::FOO . 通常,当包是一个单独的文件时,我可以在主程序中这样做:

    use MyClass qw(FOO);
    

    但是,由于我的课程和程序是一个单独的文件,所以我不能这样做。什么是我的主程序能够访问我在类中定义的常量的最好方法?

    第二期……

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

    $myHash{FOO} = "bar";
    

    问题是 %myHash 具有文本字符串 作为键而不是常量的值。当我这样做时,这会导致问题:

    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包,并且尽可能简单地工作。

    4 回复  |  直到 14 年前
        1
  •  20
  •   Eric Strom    14 年前

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

    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),可以 require 'Constants.pm'; 部分 use 将成为一个禁忌。

        2
  •  4
  •   Paul Nathan    14 年前
    1. Perl constants 不是常量。它们被编译定义为在编译时内联的一种特殊类型的函数。

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

        3
  •  3
  •   Michael Carman    14 年前

    当出现在哈希查找中时,将自动引用裸词。您需要强制实现常量的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 .

        4
  •  0
  •   dolmen    14 年前

    我第二个回答是埃里克·斯特罗姆。

    但是,这里有另一种方法(但这暴露了太多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";