我只是一个Perl的初学者,试图把我的头缠在对象上。我创建一个对象没有问题,但是,当我引入一个子类(如果术语错误,请抱歉)并将所有内容导出到主::当我所说的一切本质上是指我想要从parent. pm导出的子例程(不是方法)。
#main.pl
use A::B;
my $string = format_date();
#A.pm
package A;
use strict;
use Exporter qw(import);
our @EXPORT = qw(format_date);
sub format_date { #do stuff}
#other subroutines/methods in package A
#B.pm -> located in A/B.pm
package A::B;
use strict;
use base qw(A);
other code in package B
我期待着"使用A::B;'语法将format_date子例程加载到main::脚本。当我运行它时,我得到-未定义的子例程& main::format_date调用于.....
当我使用"使用A;在www.example.com上一切都运行良好。main.pl everything runs fine.
我错过了什么?
注意-我们的一些站点使用5.8.8,所以一些语法需要稍微老一点,比如usebase。大多数使用5.34,但不是全部。
2条答案
按热度按时间nkcskrwz1#
子类继承父类中定义的方法,但不会自动从父类导入子类。(继承更多地是一个运行时特性,而导入更多地是一个编译时特性。)
一般来说,如果你试图使用面向对象的特性来编写一个模块(比如使用继承、定义方法、构造函数、析构函数等),而这个模块又是一个导出器,那么你可能需要回到设计阶段,考虑将它分成两个独立的模块:一个面向对象的和一个函数输出器。
(It当然可以编写同时做这两件事的模块,但在大多数情况下,这表明您的设计混乱。)
j5fpnvbx2#
我错过了什么?
简而言之:
main.pl
通过子例程(format_date
)的非限定名称调用子例程,该名称从未被导入到该子例程中(此外,程序甚至不加载定义该子例程的包)。问题是这个问题混淆了 * class * 和 * package * 的概念,虽然Perl允许我们这样做,因为两者的区别是模糊的,但我们不必滥用它:你的包
A
和A::B
并不是一个类--它们不能构造一个示例(一个对象),因为没有bless作为引用对象的sub,而且它们也不使用其他面向对象的工具(没有使用所指示的继承)。然后将它们作为类层次结构来处理:问题中建立的继承不 * import * sub,如by tobyink所解释的。
解决这个问题最简单的方法是将包转换为普通类并按原样使用它们。
程序(
main.pl
)文件
A.pm
文件
A/B.pm
现在调用
perl main.pl
将打印(本地)日期Wed Jan 18 13:56:47 2023
。另一种方法是将它们作为纯粹的包,并编写
A::B
,以便它(显式地)从A
导入所需的subs,因为它们是被请求的。这要复杂得多,而且与使用类相比没有任何优势。更多信息请参见this SO page。
或者,您可以继续执行此操作,并使用实际上将
A
和A::B
视为类的代码,其中A::B
继承自A
--将format_date
作为类方法调用。因此,不要使用
my $string = format_date()
,而是使用现在
format_date
被当作一个类方法,因为它没有在A::B
中定义,所以继承层次结构被遵循,它在A
中找到。包名(A::B
)被作为第一个参数传递,方法运行。然而,我不推荐这样做,因为同时将包用作类和导出是很复杂的,使用起来也很复杂--而且没有理由这样做。
†一个类首先是一个包,参见参考文献perlobj和教程perlootut。
例如,对于一个普通的包,它从来不想成为一个类,我们 * 可以 * 调用它的subs作为
Packname->subname
--它将表现为一个 * class方法 *,其中Packname
作为第一个参数传递给subname
。但这更多的是Perl的(有意的)简单面向对象系统的副作用,不应该被滥用。我强烈建议不要混用:不要将导出包作为类使用(可能是通过添加OO特性,比如继承),也不要从类(面向对象的包,通常有一个
bless
-ing子类)中提取EXPORT
。请参见this post中的脚注和前面的文本,以获得关于Perl中类与包的更详细的说明。