【问题标题】:In Perl, what's the underlying difference between a hash and a blessed reference?在 Perl 中,哈希和祝福引用之间的根本区别是什么?
【发布时间】:2021-09-06 20:19:42
【问题描述】:

我是 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 做的一件事是通过调用ref $person1 来内省它被祝福的类的名称。您还可以安排Person 从基类继承属性。
  • 您可以使用Person 做的另一件事是提供对其数据属性的访问验证。因此,您将实现一个方法 Name(),而不是 $person1->{Name},该方法返回 $person1->{Name},并且可能会执行一些其他有用的事情,例如日志记录或检查名称是否已定义等等。
  • 这能回答你的问题吗? What exactly does Perl's "bless" do?
  • 如果您正在学习 perl 中的 OO,您可能应该花时间学习 Moo 或 Moose。 vanilla OO 功能在现代 perl 中并不常用。
  • @ceving 很抱歉没有这么清楚,问题是,Perl 对底层对象的处理方式是否与哈希、任何优化、除了 OO 的好处以及我不知道的东西有什么不同。 , 对于简单的数据对象

标签: perl oop hash bless


【解决方案1】:

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

$person2 仅供参考。

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

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

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

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

该接口可以稳定,而底层数据或结构可以更改。使用普通哈希,您的程序必须知道哈希结构的变化。

在简单的示例中,例如您展示的示例,您看不到太多好处,因为您将界面直接映射到结构。如果您查看更复杂的示例(例如复杂的 Perl 模块),您会发现您可以访问的内容不会直接映射到它们使用的数据结构上。

例如,假设您的任务的某些部分根据某人的年龄(例如有关存储人们数据的各种法律或法规)来分隔任务。或许你有方法is_underage

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

您不必将其存储为硬性答案,尤其是因为该年龄可能因司法管辖区和活动而异。但是,模块以某种方式解决了这个问题。这就是界面的重点:隐藏复杂性。

例如,请参阅How a script becomes a module。在一个扩展的示例中,我从一些简单的东西开始,但随着问题变得有点复杂,我开始四处移动并最终得到一个模块。但是,这个故事的一部分是认识到什么时候对象可能会使事情变得更简单。

这是您通过经验得出的结论。尝试两种方式。寻找你在任何一种方式上都过于努力的线索。例如,有些人已经推荐了 Moo,但考虑是否需要引入模块来做一些简单的事情。同样,如果您正在构建一个大型系统,那么框架可能是合适的。

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

【讨论】:

  • 除了更有意义之外,这使引用更小,并且复制引用(例如return $objpush @objs, $obj; 等)更快。
  • 您在技术上是正确的(最好的形式),但我想解释的只有这么多。
  • 感谢您提供信息丰富的答案,我发布的示例与我正在寻找的内容尽可能接近,假设我只需要保存简单数据(只有标量),没有函数,没有处理,没有特殊情况,只是想知道在 Perl 的引擎盖下,OO 是否比简单哈希有任何好处
  • 我不建议你做任何额外的解释,只是避免不必要的错误信息。说“被引用的哈希被祝福”就像说“引用被祝福”一样容易。
【解决方案2】:

如果您不打算使用方法调用,则没有那么大的区别。你可以用$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

【讨论】:

    猜你喜欢
    • 2021-04-01
    • 1970-01-01
    • 2010-09-28
    • 2011-05-04
    • 2011-10-29
    • 2011-01-04
    • 2011-07-07
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多