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

时间:2017-05-17 12:20:09

标签: perl perl-module

我有一个Perl脚本,我试图与两个不同的Perl环境兼容。为了解决我所使用的两个不同版本的Socket,我对require和import做了一些小问题。我已经开始工作了,但我对这种行为并不满意。

Mod.pm:

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
}

2 个答案:

答案 0 :(得分:4)

require版本打印MAGIC_CONST而不是42的原因是因为use告诉perl将符号从一个模块导入另一个模块。如果没有use,则没有定义名为MAGIC_CONST的函数,因此perl会将其解释为字符串。您应该use strict禁用将这样的裸字自动转换为字符串。

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

产生

  

不严格:MAGIC_CONST

但是

#!/usr/bin/env perl
use strict;
# forgot to define constant MAGIC_CONST...
print 'Strict:' . MAGIC_CONST . "\n";

产生错误:

  

在使用“严格潜艇”时不允许使用Bareword“MAGIC_CONST”   ./test.pl第4行。./test.pl的执行因编译而中止   错误。

因此,如果您想在另一个模块中使用一个模块的功能,您必须使用use导入它们,或者使用完整的包名称来调用它们:

package Foo;
sub MAGIC_CONST { 42 };

package Bar;
print 'Foo from Bar: ' . Foo::MAGIC_CONST . "\n";
  来自Bar的Foo: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);

答案 1 :(得分:3)

Adam's answer可以很好地解释发生了什么以及如何获得所需的行为。我建议不要使用constant.pm来定义常量的符号名称。一个相当漂亮且方便的替代方案,使用较少的陷阱来使用Const::Fast定义的常量并允许它们被导入。

此外,通过在要导入常量的模块中使用Importer,定义常量的模块可以避免继承Exporter的沉重包袱,或者必须使用{ {1}} Exporter

import允许您定义实常数组和散列的事实是一个额外的好处。

例如:

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__

作为I note in my blog post

  

f我想从配置文件中读取常量,这是微不足道的。如果我想将它们导出为JSON,YAML,INI或其他任何东西,那也是微不足道的。我可以毫不犹豫地插入它们。

     

对于那些认真对待导出变量#!/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}); } 的立场的人来说,这需要一些人习惯。请记住,警告是为了确保您不会编写无法修改全局变量的代码。但是,在这种情况下,我们导出的变量不可修改。也许你可以说服自己在这种情况下这种担忧真的不适用。如果您尝试引用不存在的常量,则会出现错误(尽管在运行时)...

在大多数情况下,这种方法的好处超过了不使用Exporter的速度惩罚。