8

我目前正在学习关于类型团和命名空间的 Perls 系统。所以我写了一个模块,它接受两个参数,一个常量的值和名称,并将常量导出给调用者。$package 变量等于 caller[2]。

*{"$package::$name"} = sub () { return $value; };

上面的代码完成了将匿名子例程导出到调用者符号表的工作。因为我的目标是构建自己的常量实现,所以子程序有一个空原型,这意味着它是一个只读子程序。

但这是我的问题:原型不起作用。所以

print &TestConst; #works well
print TestConst(); #works well
print TestConst; #Name "main::TestConst" used only once: possible typo at testscript.pl line 7.

我的想法有问题吗?还有另一种方法吗?

4

1 回答 1

10

您可以在运行时定义您想要的所有符号,但原型只会影响之后编译的代码,因为原型会影响对子调用的解析和编译方式。例如:

use strict;
use warnings;

package Foo;

BEGIN {
    *Foo::bar = sub () { 42 };
}

*Foo::baz = sub () { 43 };

my $bar = bar;
my $baz = baz;

print "bar = [$bar], baz = [$baz]\n";

If we run this, it dies with:

Bareword "baz" not allowed while "strict subs" in use at tprot.pl line 13.

That's a compile-time error caused by strict: the compiler saw the symbol baz and didn't know what it was, because the typeglob *Foo::baz does not get altered until runtime. But bar worked fine because it was defined in a BEGIN block, which executes immediately during compilation.

IOW, because barewords are ambiguous, Perl needs to know at compile-time whether it's a sub or something else. So you can install these during import (which executes in an implicit BEGIN block) but not at runtime.

Additionally, prototypes affect compilation semantics; a constant subroutine (like those made by constant.pm) gets optimized away. Other prototypes cause the parser to change its behavior (e.g. subs which can take code blocks.) The compiler has to know about all this stuff before calls to the sub are actually encountered in the code, so they can be parsed correctly. The code runs after everything is already parsed.

Calling a sub with explicit parens or with an ampersand does not have this restriction because Perl is smart enough at runtime to know that these are subroutine calls, and to look them up dynamically in the symbol table.

于 2014-07-04T07:41:55.867 回答