在 Perl 中,散列和 blessed 引用之间的根本区别是什么?
In Perl, what's the underlying difference between a hash and a blessed reference?
我是 Perl 的新手,我想 understand/know 更多地了解 OO 部分。
假设我有一个只有属性的“class”;是否有 benefits/advantages 用于创建包并祝福散列而不是直接处理散列?
为简单起见,让我们考虑以下示例:
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 是 blessed hash 而 2 是 hash reference 之外还有什么区别?
在这种情况下,使用对象比使用哈希有什么好处吗?
查看答案后:
感谢大家的帮助:)
Håkon Hægland 评论对我来说是最接近的答案,
我只是想知道,考虑到我只需要持有简单的标量,没有特殊检查,没有其他功能,class 比简单的散列有好处吗
(我知道如果我需要额外的功能和继承,class 将是正确的工具)
$person1
是参考,已经加持了。为了创建对象,Perl 将引用的数据与包名相关联。当您将该引用视为对象时,Perl 使用该包名称来查找方法。
$person2
仅供参考。
由于两者仍然只是参考,您仍然可以将每个都视为参考。这就是它仍然有效的原因:
print $person1->{Name} . "\n";
print $person2->{Name} . "\n";
你使用哪一个取决于你用它做什么。工具在上下文之外没有实用性。
您可以阅读有关面向对象思想的整本书(其中很多)。使用普通散列,你要求一个键,你会得到一个值。使用面向对象的接口,您可以使用方法要求对象为您做某事。这可能 return 一个值,或者做任何你喜欢的事情。您不必知道对象是如何工作的。
该接口可以稳定,而底层数据或结构可以更改。使用纯哈希,您的程序必须知道哈希结构的更改。
在简单的示例中,例如您提供的示例,您看不到太多好处,因为您将接口直接映射到结构。如果您查看更复杂的示例(例如复杂的 Perl 模块),您会发现您可以访问的内容不会直接映射到它们使用的数据结构上。
例如,假设您的任务的某些部分根据某人的年龄来划分任务(例如关于存储人们数据的各种法律或法规)。也许你有一个方法 is_underage
:
if( $person2->is_underage ) { ... }
您不必将其存储为硬性答案,尤其是因为该年龄可能因司法管辖区和 activity 而异。但是,模块以某种方式解决了这个问题。这就是界面的意义所在:隐藏复杂性。
例如,参见 How a script becomes a module。在一个扩展示例中,我从一些简单的事情开始,但随着问题变得有点复杂,我开始四处移动并以一个模块结束。但是,这个故事的一部分是识别对象何时可以使事情变得更简单。
这是你凭经验想出来的东西。两种方式都试试。寻找你在任何方面都过于努力的线索。例如,有些人已经推荐了 Moo,但考虑是否需要拉入模块来做一些简单的事情。同样,如果您正在构建一个大型系统,那么框架可能是合适的。
有很多人主张完全遵守 OO,但也有同样(错误的 :) 阵营一直主张裸数据结构。函数式和 OO 风格不一定是敌人,尤其是在 Perl 中。
如果您不打算使用方法调用,则没有太大区别。你可以用 $person1
做的一件事是内省 class 的名称,它是通过调用 ref $person1
得到祝福的。您还可以安排 Person
从基础 class.
继承属性
您可以使用 Person
做的另一件事是为其数据属性提供访问验证。因此,您可以实现一个方法 name()
而不是 $person1->{Name}
returns $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
我是 Perl 的新手,我想 understand/know 更多地了解 OO 部分。 假设我有一个只有属性的“class”;是否有 benefits/advantages 用于创建包并祝福散列而不是直接处理散列?
为简单起见,让我们考虑以下示例:
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 是 blessed hash 而 2 是 hash reference 之外还有什么区别?
在这种情况下,使用对象比使用哈希有什么好处吗?
查看答案后:
感谢大家的帮助:)
Håkon Hægland 评论对我来说是最接近的答案, 我只是想知道,考虑到我只需要持有简单的标量,没有特殊检查,没有其他功能,class 比简单的散列有好处吗 (我知道如果我需要额外的功能和继承,class 将是正确的工具)
$person1
是参考,已经加持了。为了创建对象,Perl 将引用的数据与包名相关联。当您将该引用视为对象时,Perl 使用该包名称来查找方法。
$person2
仅供参考。
由于两者仍然只是参考,您仍然可以将每个都视为参考。这就是它仍然有效的原因:
print $person1->{Name} . "\n";
print $person2->{Name} . "\n";
你使用哪一个取决于你用它做什么。工具在上下文之外没有实用性。
您可以阅读有关面向对象思想的整本书(其中很多)。使用普通散列,你要求一个键,你会得到一个值。使用面向对象的接口,您可以使用方法要求对象为您做某事。这可能 return 一个值,或者做任何你喜欢的事情。您不必知道对象是如何工作的。
该接口可以稳定,而底层数据或结构可以更改。使用纯哈希,您的程序必须知道哈希结构的更改。
在简单的示例中,例如您提供的示例,您看不到太多好处,因为您将接口直接映射到结构。如果您查看更复杂的示例(例如复杂的 Perl 模块),您会发现您可以访问的内容不会直接映射到它们使用的数据结构上。
例如,假设您的任务的某些部分根据某人的年龄来划分任务(例如关于存储人们数据的各种法律或法规)。也许你有一个方法 is_underage
:
if( $person2->is_underage ) { ... }
您不必将其存储为硬性答案,尤其是因为该年龄可能因司法管辖区和 activity 而异。但是,模块以某种方式解决了这个问题。这就是界面的意义所在:隐藏复杂性。
例如,参见 How a script becomes a module。在一个扩展示例中,我从一些简单的事情开始,但随着问题变得有点复杂,我开始四处移动并以一个模块结束。但是,这个故事的一部分是识别对象何时可以使事情变得更简单。
这是你凭经验想出来的东西。两种方式都试试。寻找你在任何方面都过于努力的线索。例如,有些人已经推荐了 Moo,但考虑是否需要拉入模块来做一些简单的事情。同样,如果您正在构建一个大型系统,那么框架可能是合适的。
有很多人主张完全遵守 OO,但也有同样(错误的 :) 阵营一直主张裸数据结构。函数式和 OO 风格不一定是敌人,尤其是在 Perl 中。
如果您不打算使用方法调用,则没有太大区别。你可以用 $person1
做的一件事是内省 class 的名称,它是通过调用 ref $person1
得到祝福的。您还可以安排 Person
从基础 class.
您可以使用 Person
做的另一件事是为其数据属性提供访问验证。因此,您可以实现一个方法 name()
而不是 $person1->{Name}
returns $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