- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
Perl 语言也支持面向对象的编程方法,而且它提供了两种不同的面向对象编程实现。
面向对象有很多基础概念,这里我们主要讲解三个:对象、类和方法
Perl 中有两种不同地面向对象编程的实现:
1、 基于匿名哈希表的方式;
每个对象实例的实质就是一个指向匿名哈希表的引用。这个匿名哈希表存储着所有的范例属性 2、 基于数组的方式;
在定义一个类的时候,我们将为每一个实例属性创建一个数组,而每一个对象实例的实质就是一个指向这些数组中某一行索引的引用。在这些数组中,存储着所有的范例属性
Perl 提供了 bless() 函数用来构造对象, 通过 bless 把一个引用和这个类名相关联,返回这个引用就构造出一个对象。
Perl 中一个类是一个简单的包
可以把一个包当作一个类用,并且把包里的函数当作类的方法来用。
Perl 的包提供了独立的命名空间,所以不同包的方法与变量名不会冲突。
Perl 类的文件后缀为 .pm
下面的代码创建了一个 People 类
package People;
类的代码范围到脚本文件的最后一行,或者到下一个 package 关键字前
为了创建一个类的实例 (对象) ,我们需要定义一个构造函数。
大多数程序使用类名作为构造函数,Perl 中可以使用任何名字
我们可以使用多种 Perl 的变量作为 Perl 的对象。 大多数情况下我们会使用引用数组或哈希。
接下来我们为 People 类创建一个构造函数,使用了 Perl 的哈希引用
在创建对象时,需要提供一个构造函数,它是一个子程序,返回对象的引用。
package People;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# 输出用户信息
print "名字:$self->{_firstName}\n";
print "姓氏:$self->{_lastName}\n";
print "编号:$self->{_ssn}\n";
bless $self, $class;
return $self;
}
然后使用以下语句创建一个 People 的实例 $
object
$object = new Person( "小明", "王", 23234345);
Perl 类的方法是一个 Perl 子程序,也即通常所说的成员函数。
Perl 面向对象中 Perl 的方法定义不提供任何特别语法,但规定方法的第一个参数为对象或其被引用的包。
Perl 没有提供私有变量,但我们可以通过辅助的方式来管理对象数据。
下面的代码定义了一个类方法,用来获取名字
sub getFirstName
{
return $self->{_firstName};
}
当然我们也可以这么写:
sub setFirstName
{
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
下面我们写一个范例来演示类和类方法的创建和使用
#!/usr/bin/perl
=pod
file: people.pm
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
package People;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# 输出用户信息
print "名字:$self->{_firstName}\n";
print "姓氏:$self->{_lastName}\n";
print "编号:$self->{_ssn}\n";
bless $self, $class;
return $self;
}
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
sub getFirstName {
my( $self ) = @_;
return $self->{_firstName};
}
1;
#!/usr/bin/perl
=pod
file: mail.pl
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
use People;
$object = new People( "小红", "李", 5201314);
# 获取姓名
$firstName = $object->getFirstName();
print "设置前姓名为 : $firstName\n";
# 使用辅助函数设置姓名
$object->setFirstName( "小西" );
# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";
运行main.pl 文件,输出结果如下
$ perl main.pl
名字:小红
姓氏:李
编号:5201314
设置前姓名为 : 小红
设置后姓名为 : 小西
Perl 中的类方法可以通过 @ISA 数组继承,这个数组里面包含其他包(类)的名字
Perl 中变量的继承必须明确设定
多继承就是 @ISA 数组包含多个类名字
通过@ISA 只能继承方法,不能继承数据
下面我们创建一个 Employee 类继承 People 类
#!/usr/bin/perl
=pod
file: employee.pm
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
package Employee;
use People;
use strict;
our @ISA = qw(People); # 从 People 继承
Employee 类包含了 People 类的所有方法和属性
修改我们的 main.pl 文件
#!/usr/bin/perl
=pod
file: mail.pl
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
use Employee;
$object = new Employee( "小红", "李", 5201314);
# 获取姓名
$firstName = $object->getFirstName();
print "设置前姓名为 : $firstName\n";
# 使用辅助函数设置姓名
$object->setFirstName( "小西" );
# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";
运行main.pl 文件,输出结果为:
$ perl main.pl
名字:小红
姓氏:李
编号:5201314
设置前姓名为 : 小红
设置后姓名为 : 小西
上面的范例中,Employee 类继承了 People 类,但是 People 类中的 getFirstName 方法可能没法满足我们的需求,那么我们就需要对 getFirstName 方法进行重写
下面我们将在 Employee 类中添加一些新方法,并重写了 People 类的方法
#!/usr/bin/perl
=pod
file: employee.pm
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
package Employee;
use People;
use strict;
our @ISA = qw(People); # 从 People 继承
# 重写构造函数
sub new {
my ($class) = @_;
# 调用父类的构造函数
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
# 添加更多属性
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
# 重写方法
sub getFirstName
{
my( $self ) = @_;
# 这是子类函数
print "这是子类函数\n";
return $self->{_firstName};
}
# 添加方法
sub setLastName
{
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
}
sub getLastName
{
my( $self ) = @_;
return $self->{_lastName};
}
1;
然后修改 main.pl 文件为:
#!/usr/bin/perl
=pod
file: mail.pl
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
use Employee;
$object = new Employee( "小红", "李", 5201314);
# 获取姓名,使用修改后的构造函数
$firstName = $object->getFirstName();
print "设置前姓名为 : $firstName\n";
# 使用辅助函数设置姓名
$object->setFirstName( "小西" );
# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";
运行main.pl 文件,输出结果为:
$ perl main.pl
名字:小红
姓氏:李
编号:5201314
这是子类函数
设置前姓名为 : 小红
这是子类函数
设置后姓名为 : 小西
如果一个方法,在当前类、当前类所有的基类、还有 UNIVERSAL 类中都找不到,那么就会查找名为 AUTOLOAD() 的方法。
如果找到了 AUTOLOAD,就会调用 调用,同时设定全局变量 $
AUTOLOAD 的值为缺失的方法的全限定名称
如果没有找到,那么 Perl 就会提示失败并出错
如果不希望继承基类的 AUTOLOAD,可以使用下面的代码:
sub AUTOLOAD;
当对象的最后一个引用释放时,对象会自动析构。
如果需要在析构的时候做些什么,可以通过在类中定义一个名为 DESTROY 的方法。 它将在适合的时机自动调用,并且执行额外的清理动作
package Employee;
...
sub DESTROY
{
print "Employee::DESTROY called\n";
}
Perl 会把对象的引用作为唯一的参数传递给 DESTROY。
注意
这个引用是只读的,也就是不能通过访问
$
*[0] 来修改它 但是对象自身(比如 "$
{$
*[0]" 或者 "@{$
*[0]}" 还有 "%{$
*[0]}" 等等)还是可写的
如果在析构器返回之前重新 bless 了对象引用,那么 Perl 会在析构器返回之后接着调用重新 bless 的那个对象的 DESTROY 方法。
这种机制使得我们有机会调用基类或者指定的其它类的析构器。 需要说明的是,DESTROY 也可以手工调用,但是通常没有必要这么做
在当前对象释放后,包含在当前对象中的其它对象会自动释放。
#!/usr/bin/perl
=pod
file: mail.pl
author: DDKK.COM 弟弟快看,程序员编程资料站(www.ddkk.com)
Copyright © 2015-2065 www.ddkk.com. All rights reserved.
=cut
# 下面是简单的类实现
package MyClass;
sub new
{
print "MyClass::new called\n";
my $type = shift; # 包名
my $self = {}; # 引用空哈希
return bless $self, $type;
}
sub DESTROY
{
print "MyClass::DESTROY called\n";
}
sub MyMethod
{
print "MyClass::MyMethod called!\n";
}
# 继承实现
package MySubClass;
@ISA = qw( MyClass );
sub new
{
print "MySubClass::new called\n";
my $type = shift; # 包名
my $self = MyClass->new; # 引用空哈希
return bless $self, $type;
}
sub DESTROY
{
print "MySubClass::DESTROY called\n";
}
sub MyMethod
{
my $self = shift;
$self->SUPER::MyMethod();
print " MySubClass::MyMethod called!\n";
}
# 调用以上类的主程序
package main;
print "调用 MyClass 方法\n";
$myObject = MyClass->new();
$myObject->MyMethod();
print "调用 MySubClass 方法\n";
$myObject2 = MySubClass->new();
$myObject2->MyMethod();
print "创建一个作用域对象\n";
{
my $myObject2 = MyClass->new();
}
# 自动调用析构函数
print "创建对象\n";
$myObject3 = MyClass->new();
undef $myObject3;
print "脚本执行结束...\n";
# 自动执行析构函数
运行以上范例,输出结果为:
$ perl main.pl
调用 MyClass 方法
MyClass::new called
MyClass::MyMethod called!
调用 MySubClass 方法
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
MySubClass::MyMethod called!
创建一个作用域对象
MyClass::new called
MyClass::DESTROY called
创建对象
MyClass::new called
MyClass::DESTROY called
脚本执行结束...
MyClass::DESTROY called
MySubClass::DESTROY called
如果我的 Perl 程序使用 Perl 模块,它将如何确定在哪里可以找到包含模块代码的文件? 例如,如果程序包含: use MyModule1; # Example 1 us
我在一个文件中有一些不同格式的数字:8.3、0.001、9e-18。我正在寻找一种简单的方法来读取它们并存储它们而不会损失任何精度。这在 AWK 中很容易,但在 Perl 中是如何完成的呢?我只愿意使
我在一个文件中有一些不同格式的数字:8.3、0.001、9e-18。我正在寻找一种简单的方法来读取它们并存储它们而不会损失任何精度。这在 AWK 中很容易,但在 Perl 中是如何完成的呢?我只愿意使
我正在自学 Perl,并且在我的 Windows 8 64 位系统上安装了 Strawberry。 Strawberry 命令行似乎工作正常,我在 C 驱动器上的 Strawberry 文件夹中创建了
我在 Perl 模块 IO::Socket::SSL 中发现了一个错误,我可能会修复它,但是,我担心测试修复。我从 Debian 下载了源码包(因为我打算为它制作一个 Debian 包或补丁)并查看了
我有一个 perl 文件,它使用了两个 perl 模块 A.pm 和 B.pm。 但是在 B.pm 中我需要调用 A.pm 的子程序。即使我在 A.pm 中使用并尝试使用它,我仍然遇到未定义的错误。
有没有办法在 Perl 运行时加载整个模块?我原以为我用 autouse 找到了一个很好的解决方案,但以下代码无法编译: package tryAutouse2; use autouse 'tryAu
过去,我编写过许多 perl 模块,以及不止一些独立的 perl 程序,但我之前从未发布过多文件 perl 程序。 我有一个几乎处于 beta 阶段的 perl 程序,它将被开源发布。它需要一些数据文
我有 1 个 perl 脚本,我们在其中编写了几个子例程。例子: # Try_1.pl main(); sub main{ --- --- check(); } check { -- --} 现在,
似乎 CPAN 上的一些(很多?)模块部分是使用 XS 在 C 中实现的,如果需要,可以回退到纯 perl 实现。虽然这很聪明,但它显然会损害性能,我想知道它是否会发生,以便我可以解决问题。 有没有一
我对 perl 很陌生。我希望我可以从 perl 安装一些软件包,我这样做是这样的: perl -MCPAN -e 'install VM::EC2' 我猜它由于依赖而失败,它显示: Result:
给定一个 Perl 包 Foo.pm,例如 package Foo; use strict; sub bar { # some code here } sub baz { # more
我有一个用 Perl 编写的测试生成器。它生成连接到模拟器的测试。这些测试本身是用 Perl 编写的,并通过其 API 连接到模拟器。我希望生成的代码是人类可读的,这意味着我希望它能够正确缩进和格式化
我正在学习 Perl,非常新的用户。我可以知道这些 Perl 代码之间有什么区别吗? #!/usr/bin/perl & #!/usr/bin/perl -w 最佳答案 那不是 perl 代码,它是
我不认为这是一个重复的问题。这专门针对 Perl 模块附带的脚本。 通常,在安装多个 Perl 版本时,您可以将 perl 可执行文件标记为版本号 (perl5.32),这样它们就可以在 /whate
我有一个在文件中使用 Blowfish 加密的程序和第二个 perl 程序,它提示输入用于将其解密为字符串的密码,我希望不必将解密的源代码写入硬盘驱动器,尽管将它放在内存中并不是真正的问题,因为运行程
有没有人为 Perl 中的惰性求值列表找到了一个好的解决方案?我尝试了很多方法来改变类似的东西 for my $item ( map { ... } @list ) { } 进入懒惰的评估——例如,通
我安装了多个版本的 Perl。 我已经指定了要使用的版本。但是为了验证,我想从 .pl 脚本本身输出 Perl 的版本。 这可能吗? 在 Perl 脚本中解析“perl --version”的输出似乎
人们还经常问“我怎样才能编译 Perl?”而他们真正想要的是创建一个可以在机器上运行的可执行文件,即使他们没有安装 Perl。 我知道有几种解决方案: perl2exe靛蓝之星 它是商业的。我从未尝试
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 8年前关闭。 Improve this
我是一名优秀的程序员,十分优秀!