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

Perl“use”语法是如何工作的?,perl,perl-module,Perl,Perl Module,示例代码: 下午1时 下午2时 test.pl 运行: 发生的情况是,init'hello'、'world'调用映射到m2.pm,并在那里初始化变量$a和$b 这样做是有道理的,但我不明白的是为什么test.pl中没有这些值 我想在这里做的是不是有什么根本性的错误?使用具有相同命名子例程和变量的两个模块的正确方法是什么 Perl的使用究竟是如何工作的?如果有人能将其与C的include指令进行对比,这会有所帮助 首先,一定要阅读 两个模块中都没有声明名称空间,因此所有内容都在主名称空间中。申报包

示例代码:

下午1时

下午2时

test.pl

运行:

发生的情况是,init'hello'、'world'调用映射到m2.pm,并在那里初始化变量$a和$b

这样做是有道理的,但我不明白的是为什么test.pl中没有这些值

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

Perl的使用究竟是如何工作的?如果有人能将其与C的include指令进行对比,这会有所帮助

首先,一定要阅读

两个模块中都没有声明名称空间,因此所有内容都在主名称空间中。申报包裹m1;在m1.pm和包装m2中;下午2点

至少,您应该实现导入方法或继承导出器提供的方法,以便使用模块的程序可以决定从何处导入内容

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

进一步:

避免使用$a和$b作为变量名,因为很容易将它们与sort使用的包变量$a和$b混淆

不要使用小写模块名:它们是为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;
首先,一定要阅读

两个模块中都没有声明名称空间,因此所有内容都在主名称空间中。申报包裹m1;在m1.pm和包装m2中;下午2点

至少,您应该实现导入方法或继承导出器提供的方法,以便使用模块的程序可以决定从何处导入内容

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

进一步:

避免使用$a和$b作为变量名,因为很容易将它们与sort使用的包变量$a和$b混淆

不要使用小写模块名:它们是为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;
在Perl中,use关键字与以下内容完全等效:

use Mymodule;

#is the same as

BEGIN {
   require Mymodule;
   Mymodule->import();
}
所以,如果您没有在代码中定义导入例程或从导出器继承,那么您的模块就没有将任何内容导入test.pl

正如Sinan所发现的,您没有在模块中声明包,因此它们默认为主包。在这种情况下,所有子例程都在main中,但是用my声明的词法变量的作用域仅限于它们在其中声明的文件

因此m1定义了sub init和sub printab,词汇$a和$b都在其范围内。但是,当test.pl加载m2时,init例程将被新定义覆盖,新定义不再围绕这两个词汇表关闭。因此,它正在写入包变量$main::a和$main::b,而不是printab绑定到的词汇表

如果您启用了学习时始终应该启用的警告,则会收到关于子程序重新定义的警告

您应该以以下方式启动每个模块:

package Some::Package::Name;
use warnings;
use strict;
然后在每个模块结束时使用:

1;
这是因为当您使用/需要一个模块时,它需要在最后返回一个真值,以便Perl知道它已正确加载。

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

use Mymodule;

#is the same as

BEGIN {
   require Mymodule;
   Mymodule->import();
}
所以,如果您没有在代码中定义导入例程或从导出器继承,那么您的模块就没有将任何内容导入test.pl

正如Sinan所发现的,您没有在模块中声明包,因此它们默认为主包。在这种情况下,所有子例程都在main中,但是用my声明的词法变量的作用域仅限于它们在其中声明的文件

因此m1定义了sub init和sub printab,词汇$a和$b都在其范围内。但是,当test.pl加载m2时,init例程将被新定义覆盖,新定义不再围绕这两个词汇表关闭。因此,它正在写入包变量$main::a和$main::b,而不是printab绑定到的词汇表

如果您启用了学习时始终应该启用的警告,则会收到关于子程序重新定义的警告

您应该以以下方式启动每个模块:

package Some::Package::Name;
use warnings;
use strict;
然后在每个模块结束时使用:

1;
这是因为当您使用/需要一个模块时,它需要在最后返回一个真值,以便Perl知道它已正确加载。

printab是在文件m1.pm中定义的,并且只能访问该文件范围内的$a和$b变量。m2.pm中的变量$a和$b的作用域是该文件,它们与m1.pm中的$a和$b是不同的变量

init在m2.pm中设置变量的作用域,因为这是&init函数的最后一个定义位置,所以它没有设置printab将尝试打印的相同变量。

printab在文件m1.pm中定义,并且只能访问$a和$b变量 作用域为该文件的。m2.pm中的变量$a和$b的作用域是该文件,它们与m1.pm中的$a和$b是不同的变量



init在m2.pm中设置变量的作用域,因为这是&init函数的最后一个定义位置,所以它没有设置printab将要打印的相同变量。

有关我需要它的原因,请参阅。这是您的完整代码吗?您的模块是定义导入例程还是从导出器继承。如果不是,则不会将子例程导出到测试中。pl@Eric:是的,就这些。好的,看看我的答案,为什么它不起作用。因为m1和m2说它们是他们的,其他示波器应该不戴手套。关于我为什么需要这个,请看。这是你的完整代码吗?您的模块是定义导入例程还是从导出器继承。如果不是,则不会将子例程导出到测试中。pl@Eric:是的,就这些。好的,看看我的答案,为什么它不起作用。因为m1和m2说它们是它们的,其他作用域应该远离它们。包名称必须与模块名称相同吗?我不这么认为。@Lazer=>不一定是这样,但按照惯例是这样。@Lazer:不,从技术上讲,它们不一定是一样的。然而,如果导出不同,则无法正常工作,因为正如Eric Strom所说,使用模块;加载模块后隐式执行模块->导入。如果模块中的包的名称不是模块,那么模块->导入将查看错误的包,并且无法导入任何内容。如果您不导出,那么除了约定之外,没有其他理由说明包名和模块名需要相同。包名必须与模块名相同吗?我不这么认为。@Lazer=>不一定是这样,但按照惯例是这样。@Lazer:不,从技术上讲,它们不一定是一样的。然而,如果导出不同,则无法正常工作,因为正如Eric Strom所说,使用模块;加载模块后隐式执行模块->导入。如果模块中的包的名称不是模块,那么模块->导入将查看错误的包,并且无法导入任何内容。如果您不导出,那么除了约定之外,没有其他原因可以解释为什么包名和模块名需要相同。@DVK-不,我说的是真的。在OP中每个文件的顶部添加一个包Foo不会使一个文件中的词法变量在另一个文件中可见。规则-范围是否会在同一文件中跨包边界保持?例如,A包;我的$var1=x;1.B包;打印$var1;-print$var1会在A包中看到变量delcareed吗?@DVK=>my变量是块范围的,其中文件结尾构成块结尾,因此在您的示例中,$var1在两个包中都可见。当我在一个文件中使用多个包时,我通常将整个包声明封装在一个块中:{package…;…},这样词汇就不会泄漏out@Eric-然后我站在更正,它确实是一个文件,而不是包的范围。出于某种原因,我的印象是enw包强加了新的块作用域。@DVK:不,如果需要,您需要围绕包声明显式创建一个新作用域。@DVK-不,我是说这个的。在OP中每个文件的顶部添加一个包Foo不会使一个文件中的词法变量在另一个文件中可见。规则-范围是否会在同一文件中跨包边界保持?例如,A包;我的$var1=x;1.B包;打印$var1;-print$var1会在A包中看到变量delcareed吗?@DVK=>my变量是块范围的,其中文件结尾构成块结尾,因此在您的示例中,$var1在两个包中都可见。当我在一个文件中使用多个包时,我通常将整个包声明封装在一个块中:{package…;…},这样词汇就不会泄漏out@Eric-然后我站在更正,它确实是一个文件,而不是包的范围。出于某种原因,我的印象是enw包强加了新的块作用域。@DVK:不,如果需要,您需要围绕包声明显式创建一个新作用域。