perl使用vs require和import,常量只是函数

perl使用vs require和import,常量只是函数,perl,perl-module,Perl,Perl Module,我有一个Perl脚本,我正试图使它与两个不同的Perl环境兼容。为了解决我所拥有的两个不同版本的套接字,我正在对require和import进行一些黑客操作。我已经让它工作了,但我对它的行为不满意 下午二时 package Mod; use base 'Exporter'; our @EXPORT = qw( MAGIC_CONST ); sub MAGIC_CONST() { 42; } test.pl: use Mod; #require Mod; #import Mod; printf

我有一个Perl脚本,我正试图使它与两个不同的Perl环境兼容。为了解决我所拥有的两个不同版本的套接字,我正在对require和import进行一些黑客操作。我已经让它工作了,但我对它的行为不满意

下午二时

package Mod;
use base 'Exporter';
our @EXPORT = qw( MAGIC_CONST );
sub MAGIC_CONST() { 42; }
test.pl:

use Mod;
#require Mod;
#import Mod;

printf "MAGIC_CONST = ". MAGIC_CONST ."\n";
printf "MAGIC_CONST = ". MAGIC_CONST() ."\n";
产出:

MAGIC_CONST = 42
MAGIC_CONST = 42
但是使用'require'和'import'替代,我得到了以下结果:

输出:

MAGIC_CONST = MAGIC_CONST
MAGIC_CONST = 42
所以问题是:有没有一种干净的方法可以得到常数的正常行为?我当然可以做
sub-MAGIC_-CONST{Mod::MAGIC_-CONST()

我实际上是这样做的:

use Socket;
if ($Socket::VERSION > 1.96) {
  import Socket qw(SO_KEEPALIVE); # among others
  setsockopt($s, SOL_SOCKET, SO_KEEPALIVE); # among others
}

require
version打印
MAGIC_CONST
而不是
42
的原因是
use
告诉perl将符号从一个模块导入到另一个模块。没有
use
,就没有定义名为
MAGIC\u CONST
的函数,因此perl将其解释为字符串。您应该
使用strict
来禁用将这样的单词自动转换为字符串

#!/usr/bin/env perl
no strict;
# forgot to define constant MAGIC_CONST...
print 'Not strict:' . MAGIC_CONST . "\n";
产生

不严格:魔法常数

但是

产生一个错误:

在使用“严格subs”时,不允许使用裸字“MAGIC_CONST” /test.pl第4行。由于编译,执行./test.pl被中止 错误

因此,如果要在另一个模块中使用一个模块的函数,则必须使用
use
导入它们,或者使用完整的软件包名称调用它们:

package Foo;
sub MAGIC_CONST { 42 };

package Bar;
print 'Foo from Bar: ' . Foo::MAGIC_CONST . "\n";
酒吧服务员:42

通常最好避免有条件地导入内容。您可以按以下方式解决问题:

use Socket;
if ($Socket::VERSION > 1.96) {
  setsockopt($s, SOL_SOCKET, Socket::SO_KEEPALIVE);
}
如果确实要导入,仍然需要在编译时进行导入

use Socket;
use constant qw( );
BEGIN {
  if ($Socket::VERSION > 1.96) {
     Socket->import(qw( SO_KEEPALIVE ));
  } else {
     constant->import({ SO_KEEPALIVE => undef });
  }
}

setsockopt($s, SOL_SOCKET, SO_KEEPALIVE) if defined(SO_KEEPALIVE);
对正在发生的事情以及如何获得所需的行为给出了很好的解释。我建议不要使用来定义常量的符号名。一种外观相当美观、使用方便且具有较少陷阱的替代方法是使用使用定义的常量并允许导入它们

此外,通过在想要导入常量的模块中使用,定义常量的模块可以避免继承的繁重负担,或者必须使用
导出器
导入

Const::Fast
允许您定义实常量数组和散列,这是一个额外的优点

例如:

package MyConstants;

use strict;
use warnings;

use Const::Fast;
use Socket;

const our @EXPORT => ();
const our @EXPORT_OK => qw(
    %SOCKET_OPT
);

const our %SOCKET_OPT => (
    keep_alive => ($Socket::VERSION > 1.96) ? Socket::SO_KEEPALIVE : undef,
);

__PACKAGE__;
__END__
在脚本中使用这些常量:

#!/usr/bin/env perl

use strict;
use warnings;

use Socket;
use Importer 'MyConstants' => qw( %SOCKET_OPT );

if ( defined $SOCKET_OPT{keep_alive} ) {
    setsockopt($s, SOL_SOCKET, $SOCKET_OPT{keep_alive});
}
作为:

如果我想从配置文件中读取常量,这很简单。如果我想将它们导出为JSON、YAML、INI或其他格式,这也很简单。我可以任意插入它们

对于那些认真对待导出者反对导出变量的立场的人来说,这需要一些时间来适应。请记住,警告是为了确保您编写的代码不会随意修改全局变量。但是,在这种情况下,我们导出的变量是不可修改的。也许你可以说服自己,这种担心在这种情况下并不适用。如果您试图引用一个不存在的常量,您会得到一个错误(尽管是在运行时)


在大多数情况下,这种方法的好处超过了不使用
constant.pm

的速度损失。哪些版本的套接字?您也有不同版本的Perl吗?没有
使用严格的
?您可以告诉我们Perl版本。如果你不知道答案,不要假设你能决定哪些信息与找到答案相关您为什么不想使用
use
require
之间的区别在于
use
在编译时完成,而
require
则不是。因此,当您使用
require
调用
“.MAGIC_CONST.”
时,Perl还不知道符号
MAGIC_CONST
,因为
require
只会在运行时执行。如果没有
use strict
,如果没有符号,则裸字将被视为字符串,这解释了为什么您会看到文本
MAGIC\u CONST
,而不是
42
。我支持
use strict
建议。如果您需要比使用Mod更多的控制,那么您可以编写
BEGIN{require Mod;Mod->import}
,以确保它足够早地发生,从而在解析期间定义
MAGIC_CONST
。但你为什么需要这个?您正在选择加载哪种型号的Mod吗?对我来说,这听起来有点像一个字符串。
使用strict
可以避免将裸词解释为字符串,正如亚当在回答中所解释的那样。这会更清楚地表明,即使导入常量的行在文件中出现得更早,但在太晚之前,常量实际上不会被导入。将导入包装在
开始
块中,这意味着Perl可以将剩下的代码解释为子例程名称。更新了问题,提供了一个更具体的示例,说明了我正在尝试完成的任务。我添加了解决方案。这个答案忽略了以下事实:OP具有
导入
要求
。其余的都是正确的。
sub-MAGIC_CONST{42}。。。如果没有空原型,您将放弃常量子例程的一个优点,但保留所有的缺陷和丑陋
sub-MAGIC_CONST(){42}
。我绝对支持
CONST::Fast
,我多年来一直使用它,没有任何问题。
#!/usr/bin/env perl

use strict;
use warnings;

use Socket;
use Importer 'MyConstants' => qw( %SOCKET_OPT );

if ( defined $SOCKET_OPT{keep_alive} ) {
    setsockopt($s, SOL_SOCKET, $SOCKET_OPT{keep_alive});
}