与第二个例子相比,第一个带有typeglobs的例子有缺点吗?
package Some::Module::Win32;
use strict;
use 5.10.0;
use Exporter 'import';
our @EXPORT_OK = qw(public);
use Some::Module;
*_func_one = \&Some::Module::_func_one;
*_func_two = \&Some::Module::_func_two;
*_func_three = \&Some::Module::_func_three;
sub public {
my $s = _func_one();
for my $i ( 0 .. $s ) {
say _func_two( $i );
}
say _func_three( $s );
}
1;
package Some::Module::Win32;
use strict;
use 5.10.0;
use Exporter 'import';
our @EXPORT_OK = qw(public);
use Some::Module;
sub public {
my $s = Some::Module::_func_one();
for my $i ( 0 .. $s ) {
say Some::Module::_func_two( $i );
}
say Some::Module::_func_three( $s );
}
1;
答案 0 :(得分:3)
您的第一个示例种类显示了Exporter
的工作原理:通过分配typeglobs。但是有一个重要的区别:当导入函数时。当子程序有原型时,这一点非常重要。在解析期间需要知道原型,因此必须在BEGIN
阶段知道。 use
- 通常在已使用的包上调用import
- 在BEGIN
阶段处理。
您还应该意识到,在您的第一个示例中,代码的用户现在可以Some::Module::Win32::_func_one()
,而在第二个示例中这是不可能的(除非Some::Module
导出_func_one
。
这是一个在正确阶段导入函数的版本:
package Some::Module::Win32;
use strict;
use 5.10.1; # because `parent` comes with 10.1
use parent 'Exporter'; # optimal way to inherit the `import`.
our @EXPORT_OK = qw(public);
use Some::Module;
BEGIN {
*_func_one = \&Some::Module::_func_one;
*_func_two = \&Some::Module::_func_two;
*_func_three = \&Some::Module::_func_three;
}
sub public {
my $s = _func_one();
for my $i ( 0 .. $s ) {
say _func_two( $i );
}
say _func_three( $s );
}
1;
如果您愿意,可以使用namespace::autoclean
之类的模块,在您不再需要符号表时删除任何外来导入。
另一种策略是将coderefs放入词汇变量。但是,语法有点难看,任何原型完全被忽略:
package Some::Module::Win32;
use strict;
use 5.10.1;
use parent 'Exporter';
our @EXPORT_OK = qw(public);
use Some::Module;
my $func_one = \&Some::Module::_func_one;
my $func_two = \&Some::Module::_func_two;
my $func_three = \&Some::Module::_func_three;
sub public {
my $s = $func_one->();
for my $i ( 0 .. $s ) {
say $func_two->( $i );
}
say $func_three->( $s );
}
1;
这不会触及符号表,因此可以被认为是非常“干净”的解决方案。
您的第二个版本可能更冗长,但它具有非常明确的优势,这可能使代码更容易理解为读者或维护者。这是我经常使用的解决方案。
Marpa::R2::Inner::Scanless::G::SYMBOL_IDS_BY_EVENT_NAME_AND_TYPE
)