处理相互使用的模块的最佳方法是什么?
假设我有一个具有哈希函数的模块:
# Really::Useful::Functions::On::Hash.pm
use base qw<Exporter>;
use strict;
use warnings;
use Really::Useful::Functions::On::List qw<transform_list>;
our @EXPORT_OK = qw<transform_hash transform_hash_as_list ...>;
#...
sub transform_hash { ... }
#...
sub transform_hash_as_list {
return transform_list( %{ shift() } );
}
#...
1
另一个模块已经分段列出:
# Really::Useful::Functions::On::List.pm
use base qw<Exporter>;
use strict;
use warnings;
use Really::Useful::Functions::On::Hash qw<transform_hash>;
our @EXPORT_OK = qw<transform_list some_func ...>;
#...
sub transform_list { ... }
#...
sub some_func {
my %params = transform_hash @_;
#...
}
#...
1
假设足够多的这些实用程序函数足够方便我将在BEGIN语句中使用它们并导入函数来处理参数列表或配置数据。
我一直在将子定义放入BEGIN块中,以确保只要有人包含该模块就可以使用它们。但是我已经陷入了毛茸茸的竞争条件,其中定义没有在BEGIN块中完成。
我将不断发展的代码习惯用法放入模块中,这样我就可以重复使用我发现自己编码的任何习惯用法。例如:
sub list_if {
my $condition = shift;
return unless $condition;
my $more_args = scalar @_;
my $arg_list = @_ > 1 ? \@_ : @_ ? shift : $condition;
if (( reftype( $arg_list ) || '' ) eq 'ARRAY' ) {
return wantarray ? @$arg_list : $arg_list;
}
elsif ( $more_args ) {
return $arg_list;
}
return;
}
捕获了两个我厌倦了打字的习语:
@{ func_I_hope_returns_a_listref() || [] }
和
( $condition ? LIST : ())
我在BEGIN块中定义的函数越多,我就越有可能使用这些成语砖来表达逻辑,BEGIN块中需要砖块的可能性越大。
人们是否有标准的方法来处理这种语言 - 成语砖模型?
我一直在做Pure-Perl; XS会减轻一些吗?
答案 0 :(得分:5)
如果你想拥有相互依赖的模块,一个简单的方法就是使用具有完全限定名称的后期绑定子程序调用(换句话说,在子调用上使用parens)。原型不会起作用,但perl不会关心Somepackage::mysub()
没有定义,直到你真正尝试调用它。当我编写相互依赖的模块时,我通常将它们保存在同一个文件中,通过完全避免导入来简化情况。
此外,由于sub name {...}
与BEGIN {*name = sub {...}}
相同,因此无需在BEGIN块中定义子
答案 1 :(得分:3)
如果两个模块相互依赖,则设计存在一些问题。如果我是你,我会考虑重构我的模块。
答案 2 :(得分:3)
你可以有两个模块,每个模块都调用另一个模块,因为这些调用是在运行时完成的,然后“一切”都将被加载。但是,(显然)这意味着您需要进入运行时阶段而不会爆炸。一种常见的方法是使用一些其他模块,包括这两个模块中的任何一个,use
它们两者。作为删除直接use
语句的直接结果,您将丢失这些导入,但无论如何将符号从一个模块导入到另一个模块都不是一个好主意。
查看您编写的代码,我很惊讶您已经提出了许多处理数据的“新”方法,您觉得需要将这些方法分配到单独的库中。您是否查看了标准库Hash::Util,List::Util和List::MoreUtils?我建议您使用标准库以更加惯用的Perlish方式退出库和代码。