如果我引用一个包但不使用/要求它会发生什么?

时间:2016-10-11 15:54:02

标签: perl

尽我所能(主要是为了清晰/文档),我一直试图说

use Some::Module;
use Another::Module qw( some namespaces );

在我使用其他模块的Perl模块中。

我一直在清理一些旧代码,看到我在代码中引用模块的地方,而没有use d:

my $example = Yet::Another::Module->AFunction($data); # EXAMPLE 1
my $demo = Whats::The::Difference::Here($data);       # EXAMPLE 2

所以我的问题是:

  1. 是否存在性能影响(我在思考编译时间),没有说明use x并只是在代码中引用它?
  2. 我认为我不应该use代码中没有使用的模块 - 我告诉编译器编译不必要的代码。
  3. 示例1中的调用函数与示例2的样式之间的区别是什么?

2 个答案:

答案 0 :(得分:3)

你实际上有很多问题。

  
      
  1. 是否存在性能影响(思考编译时间),没有说明使用x并只是在代码中引用它?
  2.   

不,没有性能影响,因为你不能这样做。您在工作程序中使用的每个命名空间都会在某处定义。要么use d或require更早到它被调用的地方,或者你的一个依赖项,或者用另一种方式 1 来使Perl意识到它

Perl在符号表中跟踪这些事情。它们拥有关于命名空间和变量名称的所有知识。因此,如果您的Some::Module不在引用的符号表中,Perl会抱怨。

  
      
  1. 我假设我不应该使用代码中没有使用的模块 - 我告诉编译器编译不必要的代码。
  2.   

这里毫无疑问。但是,是的,你不应该这样做。

很难说这是否会影响性能。如果您有一个只运行并运行数月的大型Catalyst应用程序,那么这并不重要。在这种情况下,启动成本通常不相关。但如果这是一个每分钟运行并处理大量数据的cronjob,那么额外的模块可能会对性能产生影响。

这实际上也是为什么所有userequire语句应该位于顶部的原因。因此,如果您需要添加或删除一些,很容易找到它们。

  
      
  1. 在示例1的样式和示例2的样式中调用函数之间有什么区别?
  2.   

这些主要用于不同的目的。

my $example = Yet::Another::Module->AFunction($data); # EXAMPLE 1

此语法与以下内容非常相似:

my $e = Yet::Another::Module::AFunction('Yet::Another::Module', $data)

它用于OOP中的类方法。最着名的一个是new,如Foo->new。它将->前面的东西传递给左边的东西包中的名为AFunction的函数(如果它是bless ed,或者它是一个标识符)作为第一个论点。但它做得更多。因为它是方法调用,所以它也需要考虑继承。

package Yet::Another::Module;
use parent 'A::First::Module';

1;

package A::First::Module;

sub AFunction { ... }

在这种情况下,您的示例也会调用AFunction,因为它继承自A :: First :: Module。除了上面引用的符号表之外,它还使用@ISA来跟踪谁从谁继承。有关详细信息,请参阅perlobj

my $demo = Whats::The:Difference::Here($data);        # EXAMPLE 2

这有语法错误。 :之后缺少The

my $demo = Whats::The::Difference::Here($data);        # EXAMPLE 2

这是一个函数调用。它会调用包Here中的函数Whats::The::Difference并传递$data,而不会传递任何其他内容。

请注意,作为Borodin points out in a comment,您的函数名称非常不典型且令人困惑。 Perl中的函数通常用全小写和下划线_而不是camel case编写。因此AFunction应为a_function,而Here应为here

1)例如,您可以在一个文件中有多个package定义,这通常不应该这样做,或者您可以使用*Some::Namespace::frobnicate = sub {...}之类的语法将内容直接分配到命名空间中。还有其他方法,但这个答案有点超出范围。

答案 1 :(得分:3)

我会说,如果你不确定,那么这就属于抢先优化的范畴,然后将其保留在中。如果删除它们,则必须包含一些未使用的库

Perl通常隐藏一个简单机制背后的复杂问题,通常做你的意思而不用太多想法

简单的机制就是这些

  • use My::Module 'function'与撰写

    相同
    BEGIN {
        require My::Module;
        My::Module->import( 'function' );
    }
    
  • perl第一次成功执行require语句时,它会向全局%INC哈希添加一个元素,该哈希具有“路径化”模块名称(在本例中为My/Module.pm })对于一个键和绝对位置,它将源代码作为值

  • 如果遇到同一模块的另一个require(也就是说,它已存在于%INC哈希中),那么require什么都不做

所以你的问题

如果我引用了一个包但却没有use / require会怎么样?

我们将会遇到使用利用包含参考的问题,所以当我的意思是Perl语言时,我只引用userequire

保持简单,这是三种可能性

  • 如上所述,如果同一模块源多次看到require,则在第一次之后会被忽略。唯一的开销是检查%INC

  • 中是否有相应的元素
  • 显然,如果您use源文件不需要,那么您正在进行不必要的编译。但是Perl非常快,除非你有一个使用大量库并且看起来像use Catalyst; print "Hello, world!\n";的程序

  • ,否则你只能在构建时间内剃掉几分之一秒。
  • 我们知道如果对从未编译过的类库进行方法调用会发生什么。我们得到

    Can't locate object method "new" via package "My::Class" (perhaps you forgot to load "My::Class"?)
    
  • 如果您使用的是功能库,那么重要的是use

    的部分
    My::Module->import( 'function' );
    

    因为第一部分是require,我们已经知道require从未做过两次。调用import通常是一个简单的函数调用,通过避免它可以节省一些重要的事情

  • 可能不太明显的是包含多个子公司的大型模块。例如,如果我只写

    use LWP::UserAgent;
    

    然后它知道它可能需要什么,这些模块也将被编译

    Carp
    Config
    Exporter
    Exporter::Heavy
    Fcntl
    HTTP::Date
    HTTP::Headers
    HTTP::Message
    HTTP::Request
    HTTP::Response
    HTTP::Status
    LWP
    LWP::MemberMixin
    LWP::Protocol
    LWP::UserAgent
    Storable
    Time::Local
    URI
    URI::Escape
    

那是在忽略pragma!

你有没有觉得自己在踢脚跟等待LWP程序编译?

我想说,为了保持Perl代码的清晰和整洁,从编译阶段删除不必要的模块可能是个主意。但是,在进行任何移交前整理之前,不要为此烦恼,对您的构建时间进行基准测试。没有人会感谢你将构建时间减少了20ms,然后因为你删除了一个非显而易见的要求而导致他们工作了几个小时。