【问题标题】:Inheriting a function with typeglobs使用 typeglob 继承函数
【发布时间】:2013-08-31 08:26:11
【问题描述】:

与第二个例子相比,第一个带有 typeglob 的例子有缺点吗?

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;

【问题讨论】:

    标签: perl function inheritance perl-module typeglob


    【解决方案1】:

    您的第一个示例某种展示了Exporter 的工作原理:通过分配类型球。但是有一个重要的区别:什么时候函数被导入。当子程序具有原型时,这一点最为重要。原型需要在解析期间知道,因此必须在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 之类的模块在您不再需要它们时从符号表中删除任何外部导入。

    另一种策略是将代码引用放入词法变量。但是,语法有点难看,任何原型都完全被忽略:

    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
    • 明确
    • 没有命名空间污染

    【讨论】:

    • 显然没有什么技术要补充,但可读性 +1。保留聪明的代码,以备不时之需。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    相关资源
    最近更新 更多