美文网首页程序员Perl小推车
第九章 管理真实的程序(四) -模块

第九章 管理真实的程序(四) -模块

作者: 可以没名字吗 | 来源:发表于2016-03-22 19:53 被阅读108次

    模块

    之前我们介绍了如何使用函数、类和数据结构来组织代码,接下来要介绍的是另一个用来组织代码和扩展代码的机制--模块。一个模块就是一个文件包,可以用use或require 来加载。模块必须要是有效的Perl代码。模块必须以一个真值结尾,这样Perl解析器才能知道模块是否被成功的加载和编译。

    当你加载一个模块时,Perl以双冒号分割模块名转换成文件路径。例如,use StrangeMonkey::Persistence;Perl就会在@INC中查找每一个叫StrangeMonkey的目录,并且在每一个叫StrangeMonkey的目录中查找一个名字为Persistence.pm的文件(实际上就是找StrangeMonkey/Persistence.pm文件);use StrangeMonkey::UI::Mobile; Perl就会在@INC中查找StrangeMonkey/UI/Mobile.pm文件。

    使用模块来组织代码

    Perl并不强制要求你使用模块、包或名字空间,你可以将所有代码都放入单个.pl文件或多个.pl文件,可以选择最舒服的方式灵活地来开发、管理、部署你的代码,当然这其中的风险和收益就取决于你自己的经验水平了。

    尽管如此,我们建议你在代码量超过几百行后就使用模块来组织代码:

    • 模块会强制在系统的不同实体之间进行逻辑分离。
    • 无论你是否使用OO,模块都能提供API边界。
    • 模块提倡以一种自然的方式来组织源代码。
    • Perl生态系统中有很多工具专门用于创建、组织、部署和分发模块。
    • 模块提供了代码重用的机制。

    即使你不使用面向对象,模块也能帮助对代码进行更好地封装。

    ****使用和导入****
    当你使用use加载一个模块时,Perl就会从磁盘中加载文件,然后调用它的import()方法(如果有参数的话还会传递参数)。按照惯例,一个模块的import()方法,会将一系列名字、导出函数和其他符号标记导入到自己的名字空间。当然这只是一个约定,模块也有可能拒绝提供import()函数或者import()函数执行的是其他行为,如编译指示strict ,作用是在调用者的词法范围内改变行为而不是导出符号:

    use strict;
    # ... calls strict->import()
    
    use CGI ':standard';
    # ... calls CGI->import( ':standard' )
    
    use feature qw( say switch );
    # ... calls feature->import( qw( say switch ) )
    

    关键字no会调用模块的unimport()方法(有参数还会传递参数)。最常见的就是搭配import() 来改变程序的行为:

    use strict;
    # no symbolic references or barewords
    # variable declaration required
    
    {
    no strict 'refs';
    # symbolic references allowed
    # strict 'subs' and 'vars' still in effect
    }
    

    use和no都会在编译的时候就生效:

    use Module::Name qw( list of arguments );
    
    #等同于
    BEGIN
    {
    require 'Module/Name.pm';
    Module::Name->import( qw( list of arguments ) );
    }
    

    类似的:

    no Module::Name qw( list of arguments );
    
    #等同于:
    BEGIN
    {
    require 'Module/Name.pm';
    Module::Name->unimport(qw( list of arguments ));
    }
    

    都是可选的!
    如果模块没有import()或unimport()函数Perl也不会报错。

    你也可以直接调用import()和unimport()函数,尽管在BEGIN块之外它们没有什么作用;编译结束后 import()和unimport()就没什么用了。

    use和require都是区分大小写的,所以use strict和use Strict是不一样的:一个是加载strict.pm,一个是加载Strict.pm。但你的操作系统或文件系统可能不会区分大小写,对于一个不区分大小写的文件系统,use strict在找不到strict.pm文件时Perl会去加载Strict.pm,但是当你尝试调用Strict->import()时却什么都不会发生,所以谨慎对待大小写总是好的。

    ****导出****
    一个模块可以通过导出自己的全局包符号,这样别的包就可以直接或间接调用import()来使用这些符号。

    核心模块Exporter就是导出符号的标准途径。Exporter依赖2个全局变量@EXPORT_OK和@EXPORT,它们包含了一系列要导出的符号。

    模块StrangeMonkey::Utilitie提供了几个单独的函数:

    package StrangeMonkey::Utilities;
    
    use Exporter 'import';
    
    our @EXPORT_OK = qw( round translate screech );
    ...
    

    任何其他的代码都可以使用这个模块和导入这些函数(round,translate,screech)。你也可以导出变量:

    push @EXPORT_OK, qw( $spider $saki $squirrel );
    

    也可以使用@EXPORT代替@EXPORT_OK来实现类似的功能:

    our @EXPORT = qw( monkey_dance monkey_sleep );
    

    这样在任何地方使用use StrangeMonkey::Utilities都会导入这些函数。要明白的是如果指定的要导入的符号,那就不会导入其他的符号;你只会得到你想要的。若要加载一个模块,但是不想导入任何符号,那就使用明确的空列表:

    # make the module available, but import() nothing
    use StrangeMonkey::Utilities ();
    

    不使用导入列表,也总是可以通过使用完全限定名来调用函数的(这你应该知道的吧):

    StrangeMonkey::Utilities::screech();
    

    简化导出
    CPAN模块Sub::Exporter提供了更友好的接口来导出函数。
    CPAN模块Moose::Exporter用于基于Moose的系统。

    相关文章

      网友评论

        本文标题:第九章 管理真实的程序(四) -模块

        本文链接:https://www.haomeiwen.com/subject/dygqlttx.html