代码之家  ›  专栏  ›  技术社区  ›  Aakash Goel

Perl“use”语法是如何工作的?

  •  0
  • Aakash Goel  · 技术社区  · 14 年前

    样本代码:

    m1.pm

    my $a;
    my $b;
    sub init {
        $a = shift;
        $b = shift;
    }
    
    sub printab {
        print "a = -$a-\n";
        print "b = -$b-\n";
    }
    
    1;
    

    m2.pm

    my $a;
    my $b;
    sub init {
        $a = shift;
        $b = shift;
    }
    
    1;
    

    test.pl

    use strict;
    use warnings;
    
    use m1;
    use m2;
    
    init('hello', 'world');
    printab();
    

    运行:

    $ perl test.pl
    a = --
    b = --
    $
    

    发生的是 init('hello', 'world') 呼叫被映射到 M2 PM 并初始化变量( $a $b )在那里。

    这是有道理的,但我不明白为什么这些价值观在 测试.pl .

    • 我想在这里做的是什么根本性的错误吗? 使用具有相同命名子例程和变量的两个模块的正确方法是什么?

    • Perl的具体功能是什么 use 工作?如果有人能把它和C做对比,那会有帮助的。 #include 指令。

    3 回复  |  直到 14 年前
        1
  •  8
  •   Sinan Ünür    14 年前

    首先,请务必阅读 perldoc perlmod .

    您不在任何一个模块中声明命名空间,因此所有内容都在 main 命名空间。申报 package m1; 在里面 m1.pm package m2; 在里面 m2.pm .

    至少,您应该实现 import 方法(或继承方法) Exporter 提供)以便使用模块的程序可以决定从何处导入。

    在我看来,你也在探索OO的边缘。

    进一步:

    • 避免使用 $a $b 作为变量名,因为很容易将它们与包变量混淆 美元 美元 使用人 sort .

    • 不要使用小写模块名:它们是为pragmata保留的。

    一个最小的实现(为了方便测试而在一个文件中)如下所示:

    package My::M1;
    
    use strict; use warnings;
    
    sub new { my $class = shift; bless { @_ } => $class }
    
    sub a {
        my $self = shift;
        my ($v) = @_;
        $self->{a} = $v if @_;
        return $self->{a};
    }
    
    sub b {
        my $self = shift;
        my ($v) = @_;
        $self->{b} = $v if @_;
        return $self->{b};
    }
    
    package My::M2;
    
    use strict; use warnings;
    use base 'My::M1';
    
    sub printtab {
        my $self = shift;
        for my $x (qw(a b)) {
            printf "%s = -%s-\n", $x, $self->$x;
        }
    }
    
    package main;
    
    my $m = My::M2->new(a => 'hello', 'b' => 'world');
    $m->printtab;
    
        2
  •  13
  •   Eric Strom    14 年前

    在Perl中, use 关键字完全等同于以下内容:

    use Mymodule;
    
    #is the same as
    
    BEGIN {
       require Mymodule;
       Mymodule->import();
    }
    

    因此,如果您没有在代码中定义导入例程(或者继承自 Exporter ,那么您的模块不会将任何内容导入到 test.pl

    正如Sinan捕获的,您没有在模块中声明包,因此它们默认为 main 包裹。在这种情况下,所有子例程都在 主要的 但是词汇变量(用 my )仅限于声明它们的文件范围。

    所以 m1 定义 sub init sub printab 词汇 $a $b 在范围内。但是什么时候 测试.pl 荷载 m2 , the init 例程将被新的定义覆盖,该定义不再围绕两个词汇关闭。所以它正在写入包变量 $main::a $main::b 而不是那些 printab 一定会的。

    如果启用了警告(学习时应该始终启用),则会警告您重新定义子例程。

    您应该用以下代码启动每个模块:

    package Some::Package::Name;
    use warnings;
    use strict;
    

    然后在每个模块末尾加上:

    1;
    

    这是因为当你 use/require 作为一个模块,它需要在末尾返回一个真正的值,以便Perl知道它已经正确加载。

        3
  •  2
  •   mob    14 年前

    printab() 在文件中定义 m1.pm 而且只能访问 $a $b 限定到该文件范围的变量。变量 美元 美元 在里面 m2.pm 是该文件的作用域,它们是 不同的变量 美元 美元 在里面 M1.PM .

    init() 设置变量范围 M2 PM (因为那是最后一个 &init 函数已定义),因此它没有设置与 printab()。 将尝试打印。