perl 从父类导入子例程

x7rlezfr  于 2023-01-21  发布在  Perl
关注(0)|答案(2)|浏览(189)

我只是一个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,但不是全部。

nkcskrwz

nkcskrwz1#

子类继承父类中定义的方法,但不会自动从父类导入子类。(继承更多地是一个运行时特性,而导入更多地是一个编译时特性。)
一般来说,如果你试图使用面向对象的特性来编写一个模块(比如使用继承、定义方法、构造函数、析构函数等),而这个模块又是一个导出器,那么你可能需要回到设计阶段,考虑将它分成两个独立的模块:一个面向对象的和一个函数输出器。
(It当然可以编写同时做这两件事的模块,但在大多数情况下,这表明您的设计混乱。)

j5fpnvbx

j5fpnvbx2#

我错过了什么?
简而言之:main.pl通过子例程(format_date)的非限定名称调用子例程,该名称从未被导入到该子例程中(此外,程序甚至不加载定义该子例程的包)。
问题是这个问题混淆了 * class * 和 * package * 的概念,虽然Perl允许我们这样做,因为两者的区别是模糊的,但我们不必滥用它:你的包AA::B并不是一个类--它们不能构造一个示例(一个对象),因为没有bless作为引用对象的sub,而且它们也不使用其他面向对象的工具(没有使用所指示的继承)。
然后将它们作为类层次结构来处理:问题中建立的继承不 * import * sub,如by tobyink所解释的。
解决这个问题最简单的方法是将包转换为普通类并按原样使用它们。
程序(main.pl

use warnings;
use strict;
use feature 'say';

use A::B; 

my $obj = A::B->new;

my $string = $obj->format_date();
say $string;

文件A.pm

package A; 

use warnings;
use strict;

sub new { bless {}, shift }  # make it a proper constructor...

sub format_date { return scalar localtime } 

# other subroutines/methods in package A 

1;

文件A/B.pm

package A::B; 

use warnings;
use strict;

use parent qw(A);  # or, if you must: use base qw(A)

# other code in package B 

1;

现在调用perl main.pl将打印(本地)日期Wed Jan 18 13:56:47 2023
另一种方法是将它们作为纯粹的包,并编写A::B,以便它(显式地)从A导入所需的subs,因为它们是被请求的。这要复杂得多,而且与使用类相比没有任何优势。
更多信息请参见this SO page
或者,您可以继续执行此操作,并使用实际上将AA::B视为类的代码,其中A::B继承自A--将format_date作为类方法调用。
因此,不要使用my $string = format_date(),而是使用

my $string = A::B->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中类与包的更详细的说明。

相关问题