在 Perl 中,哈希和祝福引用之间的潜在区别是什么?



我是Perl的新手,我想了解/了解更多关于OO部分的信息。说我有一个";类";只有属性;与直接处理哈希相比,创建包并祝福哈希有什么好处/优势吗?

为了简单起见,让我们考虑以下示例:

package Person;
sub new {
my $class = shift;
my $args = {Name => '', Age => 0, @_};

my $self = { Name => $args->{Name},
Age => $args->{Age}, };

bless $self, $class;
}

package main;
my $person1 = Person->new(Name => 'David', Age => 20);
my $person2 = {Name => 'David', Age => 20, Pet => 'Dog'};
print $person1->{Name} . "n";
print $person2->{Name} . "n";

我想知道的是$person1$person2之间的区别是什么,除了OO部分之外,除了1是一个幸运的哈希,2是一个哈希引用这一事实之外?

在这种情况下,与处理哈希相比,处理对象有什么好处吗?

查看答案后:

感谢所有的帮助:(

Håkon Hægland的评论对我来说是最接近的答案,我只是想知道,考虑到我只需要持有,简单的标量,没有特殊的检查,没有其他功能,一个类比一个简单的散列有好处吗(我知道,如果我需要额外的功能和继承,类将是正确的工具(

$person1是一个受到祝福的引用。为了创建对象,Perl将引用的数据与包名称相关联。当您将该引用视为对象时,Perl会使用该包名称来查找方法。

$person2只是一个参考。

由于两者仍然只是引用,所以您仍然可以将它们视为引用。这就是为什么它仍然有效:

print $person1->{Name} . "n";
print $person2->{Name} . "n";

你使用哪一个取决于你用它做什么。工具在上下文之外没有实用性。

你可以阅读整本关于面向对象思想的书(其中很多(。使用普通散列,你需要一个密钥,你就会得到一个值。使用面向对象的接口,可以使用方法要求对象为您做一些事情。这可能会返回一个值,或者做任何其他你喜欢的事情。你不必知道对象是如何工作的。

该接口可以是稳定的,而底层数据或结构可以更改。使用普通散列,程序必须注意散列结构的变化。

在简单的例子中,比如您所展示的例子,您看不到太多好处,因为您将接口直接映射到结构。如果您查看更复杂的示例(例如复杂的Perl模块(,您会发现您可以进行访问的事情并没有直接映射到它们所使用的数据结构上。

例如,假设你任务的某个部分根据某人的年龄来隔离任务(例如关于存储他人数据的各种法律或法规(。也许你有一个方法is_underage:

if( $person2->is_underage ) { ... }

你不一定认为这是一个硬性的答案,尤其是因为这个年龄可能因司法管辖区和活动而异。但是,不知怎么的,模块解决了这个问题。这就是界面的意义:隐藏复杂性。

例如,请参阅脚本如何成为模块。在一个扩展示例中,我从简单的东西开始,但随着问题变得更加复杂,我开始四处移动,最后得到一个模块。但是,这个故事的一部分是认识到一个物体什么时候可以让事情变得更简单。

这是你凭经验想出来的。双管齐下。寻找你在任何一方面都过于努力的线索。例如,有些人已经推荐了Moo,但请考虑是否需要引入模块来做一些简单的事情。同样,如果你正在制作一个大系统,那么一个框架可能是合适的。

有很多人主张完全遵循OO,但也有一个同样(错误的:(的阵营一直主张裸数据结构。函数式和OO风格不一定是敌人,尤其是在Perl中。

如果您不打算使用方法调用,就没有那么大的区别。使用$person1可以做的一件事是通过调用ref $person1来内省它被祝福进入的类的名称。您还可以安排Person从基类继承属性。

使用Person可以做的另一件事是为其数据属性提供访问验证。因此,您将实现一个返回$person1->{Name}的方法name(),而不是$person1->{Name},它可能会做一些其他有用的事情,如日志记录或检查是否定义了名称等等

例如:

#! /usr/bin/env perl
package LivingBeing;
use strict;
use warnings;
sub new {
die "LivingBeing: Wrong number of arguments to the constructor!" if @_ != 2;
my ( $class, $type ) = @_;
return bless {type => $type}, $class;
}
package Person;
use strict;
use warnings;
use parent -norequire => qw(LivingBeing);
sub new {
my ($class, %args) = @_;
my $self = $class->SUPER::new('human');
$self->{age} = 0;  # Default value
$self->{$_} = $args{$_} for keys %args;  # Maybe override default values..
return $self;
}
sub name {
my $self = shift;
my $name = $self->{name};
warn "Undefined name attribute" if !defined $name;
return $name;
}
package main;
use strict;
use warnings;
use feature qw(say);
my $person1 = Person->new(pet => 'cat', age => 20);
my $person2 = {name => 'David', age => 20, pet => 'dog'};
say "person1 is a : ", ref $person1;
say "person2 is a : ", ref $person2;
say "The name of person1 is: ", $person1->name;
say "The age of person1 is: ", $person1->{age};

输出

person1 is a : Person
person2 is a : HASH
Undefined name attribute at ./p2.pl line 28.
Use of uninitialized value in say at ./p2.pl line 43.
The name of person1 is: 
The age of person1 is: 20

相关内容

最新更新