我编写了一些Perl代码,它构成了基础代码中固有的两个类。我想它会打印出像这样的东西
Mik: Meow! Meow!
Sat: Woof! Woof!
但它实际上是这样印刷的:
Sat: Woof! Woof!
Sat: Woof! Woof!
,
package Animal;
sub new {
my $obj = shift;
my $name = shift;
our %pkg = ( 'name' => $name );
bless \%pkg, $obj;
return \%pkg;
}
package Cat;
@ISA = ("Animal");
sub new {
my $obj = shift;
my $name = shift;
my $self = $obj->SUPER::new($name);
return $self;
}
sub get_name {
my $obj = shift;
return $obj->{'name'};
}
sub talk {
my $obj = shift;
return "Meow! Meow!";
}
package Dog;
@ISA = ("Animal");
sub new {
my $obj = shift;
my $name = shift;
my $self = $obj->SUPER::new( $name );
return $self;
}
sub get_name {
my $obj = shift;
return $obj->{'name'};
}
sub talk {
my $obj = shift;
return "Woof! Woof!";
}
package Main;
my $cat = new Cat('Mike');
my $dog = new Dog('Sat');
print $cat->get_name() . ": " . $cat->talk() , "\n";
print $dog->get_name() . ": " . $dog->talk() , "\n";
但是如果我以这种方式更改调用者,它会打印出我想要的内容。因此,在$cat
实例化后,$dog
对象被覆盖的原因很奇怪?
package Main;
my $cat = new Cat('Mily');
print $cat->get_name() . ": " . $cat->talk() , "\n";
my $dog = new Dog('Sat');
print $dog->get_name() . ": " . $dog->talk() , "\n";
答案 0 :(得分:8)
你为什么要加入一个全局变量?将构造函数更改为:
sub new {
my $obj = shift;
my $name = shift;
my %pkg = ( 'name' => $name );
bless \%pkg, $obj;
return \%pkg;
}
更好的是,将其改为更惯用的东西:
sub new {
my $class = shift;
my $name = shift;
my $self = { name => $name };
return bless $self, $class;
}
继续前进:
为什么要在每种动物中实施new
和get_name
?这两种方法都可以继承。虽然我们正在努力,但我们还是可以摆脱@ISA
:
package Animal;
sub new {
my $class = shift;
my $name = shift;
my $self = { name => $name };
return bless $self, $class;
}
sub get_name {
my $self = shift;
return $self->{'name'};
}
package Cat;
use base qw/ Animal /;
sub talk {
my $self = shift;
return "Meow! Meow!";
}
package Dog;
use base qw/ Animal /;
sub talk {
my $self = shift;
return "Woof! Woof!";
}
package Main;
my $cat = Cat->new('Mike');
my $dog = Dog->new('Sat');
print $cat->get_name() . ": " . $cat->talk() , "\n";
print $dog->get_name() . ": " . $dog->talk() , "\n";
请问您关注哪个教程或书籍?
虽然上述情况非常好,但您可以使用Modern Perl方式:
package Animal;
use Moose;
has name => ( required => 1, is => 'rw', isa => 'Str' );
package Cat;
use Moose;
extends 'Animal';
has talk => ( default => "Meow! Meow!", is => 'ro' );
package Dog;
use Moose;
extends 'Animal';
has talk => ( default => "Woof! Woof!", is => 'ro' );
package Main;
my $cat = Cat->new( name => 'Mike');
my $dog = Dog->new( name => 'Sat');
print $cat->name . ": " . $cat->talk , "\n";
print $dog->name . ": " . $dog->talk , "\n";
答案 1 :(得分:4)
您已声明变量以使用
存储实例数据our %pkg
这是单个数据结构(%Animal::pkg
)的别名,因此所有对象都使用相同的哈希。将our
更改为my
,以便每次都创建新哈希。
值得注意的是,Perl中的“由内向外”对象可以并且确实在包中使用共享数据结构来存储实例数据,但是还需要一个额外的抽象级别来完成这项工作,我不知道不建议用它们开始OO Perl,它们是一种后天的味道。
答案 2 :(得分:2)
简而言之:our
声明包变量,因此每次执行our %pkg = (...)
时,都会为同一个变量赋值。由于所有\%pkg
引用都指向同一个var,因此new
的所有返回值都是同一个对象。引用只能被祝福到一个类中,所以最后一个获胜。
只需将our
更改为my
,它就可以正常运行。