什么是Perl中的@ISA?

Jim*_*Jim 6 perl perl-module

如果我有一个有方法的模块a,并b与要导出他们我做的:

use Exporter;  
our @ISA = qw (Exporter);  
our @EXPORT = qw (a b);  
Run Code Online (Sandbox Code Playgroud)

我不明白的是这一行:
our @ISA = qw (Exporter);做什么?

fri*_*edo 12

@Foo::ISA数组是一个全局变量,用于保存类Foo继承的类.

一般来说,你不应该@ISA直接操纵; 这样做表明你可能正在查看旧的Perl代码.

如果要声明继承关系,更好的方法是

use parent 'Exporter';
Run Code Online (Sandbox Code Playgroud)

它会@ISA在幕后为你调整,还会做一些其他有用的东西.

在你的情况下,当你这样做

our @ISA = qw(Exporter)
Run Code Online (Sandbox Code Playgroud)

你宣布你的班级是你的一个子类Exporter.的Exporter类提供一个调用的方法import.你为什么这么想?因为当你说

use MyClass;
Run Code Online (Sandbox Code Playgroud)

实际发生的是:

BEGIN { 
    require 'MyClass.pm';
    MyClass->import;
};
Run Code Online (Sandbox Code Playgroud)

import每当有人use上课时,都会自动调用该方法.该方法可以做任何你想做的事情.(import如果你愿意,你可以自己编写)但通常它用于将符号导入调用者的命名空间.这Exporter对你有什么用.

但是,Exporter也会导出自己的import方法,因此您实际上不必再继承它.(这个问题在很久以前就得到了解决.)所以现在你可以说

use Exporter qw(import);
Run Code Online (Sandbox Code Playgroud)

而你的包将获得import方法而不必乱用@ISA.


Dav*_* W. 7

在这里思考面向对象.

可以认为Exporter不仅仅是一个模块,而是一个.可以想象"我的模块出口商子类ISA "中的" 是一个 ".

你正在做的是将你的模块声明为Exporter类的子类,这意味着你可以使用importExporter类的方法,这种方法很有用.

要真正解释Exporter正在做什么,您必须了解Perl使用命名空间.想象一下,如果您的程序调用了变量1$total,那么您正在使用的模块也是如此.您的$total变量会干扰模块的$total变量.

为了防止这种情况,Perl使用名称空间.您的程序在默认名称空间中运行main.您的模块使用该package函数来声明新的命名空间.现在,您和您的模块都可以安全地使用一个名为的变量$total.在你的程序中,它确实是$main::total,并且在包中,它是$ Package :: Name :: total . If you want to use something from one _namespace_ in another, you can prepend the _namespace_ on it. Think of the$ File :: Find :: name and$ File :: Find :: dir variables you have when you useFile :: Find`.

Exporter的import方法所做的是将子例程(如果您愿意,您的变量)从命名空间复制到当前命名空间.想象一下,使用该File::Copy模块时无法将子例程复制copy到主命名空间.你仍然可以使用它,但你必须在它上面给它命名空间的名称:

use File::Copy;

...

File::Copy::copy( $from_file, $to_file );
Run Code Online (Sandbox Code Playgroud)

由于Exporter(以及导入方法),您放入packages @EXPORT数组的任何子例程都将复制到当前命名空间.因此,您可以s像这样访问File :: Copy copy`子例程:

use File::Copy;

...

copy ( $from_file, $to_file );
Run Code Online (Sandbox Code Playgroud)

这也是为什么你必须声明所有这些变量作为our和不my.my变量是词法范围的,不能在它们声明的位置之外访问.包变量(如$File::Find::name)可以.为了Exporter找到你的@EXPORT@EXPORT_OK数组,这些需要是变量.

现在,出口功能的可取性......

我们所知道和最喜欢的最古老的模块无情地导出子程序.您可以使用File :: Copy,File :: Path,File :: Find,并且可以立即访问其子例程.这是因为他们将子程序放入@EXPORT数组中.这曾经被认为是可取的,因为它使您可以立即使用这些功能.

较新的模块File::Temp需要您声明要导入的子例程:

use File::Temp qw(tempdir);

...
my $temp_dir = tempdir;
Run Code Online (Sandbox Code Playgroud)

如果我没有qw(tempdir),我就无法使用该tempdir功能.

这被认为是礼貌的.该模块要求您允许导入该功能.这是通过将子程序放入其中来完成的@EXPORT_OK.这些只会根据要求出口.

这样做更好,因为您不必导入所有内容,只需要导入.而且,您正在记录这些功能的定义位置.

面向对象的模块根本不导出任何内容,也不需要使用Exporter.自从我编写了一个使用Exporter的模块以来,已经有很长一段时间了.

- 1我们在这里谈论变量.包变量随处可见.


amo*_*mon 3

@ISA变量用于指定类之间的继承。不鼓励您自己操纵此变量。如果你想从另一个类继承,那么

use parent 'Parent::Class';
Run Code Online (Sandbox Code Playgroud)

或 v10.1 之前版本:

use base 'Parent::Class';
Run Code Online (Sandbox Code Playgroud)

在这种特定情况下,继承自Exporter使得该import方法可用。您的代码可以重写为。

use parent 'Exporter';
our @EXPORT = qw/a b/;
Run Code Online (Sandbox Code Playgroud)

import当你的模块被调用时,该方法会被自动调用use,并且可能会将符号导出到 using 包中。


为什么手动使用@ISA不好:

  • 不要分配给@ISA:其他模块可能已经向其中添加了条目;这会覆盖它们。所以,push @ISA, "Some::Class"

  • 避免@ISA在运行时修改。最好尽早指定继承关系(在解析期间或初始编译之后),以便您的模块可以不受限制地在那里使用。您可以将其包装在BEGINorCHECK块中,例如

    BEGIN {
      push @ISA, "Some::Class";
    }
    
    Run Code Online (Sandbox Code Playgroud)

通过继承parent使这变得更加容易。parent如果尚未加载,还将编译所请求的模块:不需要use Some::Class.