【问题标题】:To bless or not to bless, that is my question!祝福还是不祝福,这是我的问题!
【发布时间】:2011-03-28 04:01:22
【问题描述】:

来自新手用户的第一篇文章。我在谷歌上搜索的每一个问题似乎都会把我带到这里,而且我总是能得到很好的答案。所以当我开始思考 Perl 中祝福的用法时,这自然是我的第一站。

我刚刚进入 Perl 的 OOP,今天才读到帖子询问 bless 是做什么的。我现在明白它会将标量/哈希/数组引用到一个对象,如果你愿意的话,可以“附加”它。

在我在 Perl 中看到的大多数类示例中,它们似乎没有我在其他语言中看到的属性...

{ package Person;
    my $property = "This is what I'm talking about :)";

    sub new { ... }
    ...
}

所以,我创建了一个带有属性的愚蠢类来看看会发生什么。我立即给该属性值“NIL”,然后“Not Nil!”在构造函数中。使用方法 LIST,我能够打印该属性,并且正如我所料,它打印了 'Not Nil!'

我的问题是,如果属性的工作方式与我预期的一样(在正文中声明),那么为什么要使用 bless 呢?当您可以简单地将标量/哈希/数组创建为属性,或者创建您想要的任何引用作为属性时,拥有该引用的额外好处是什么?

我希望我能很好地解释我想要问的问题,用 Perl 非常绿色:)

【问题讨论】:

  • 我想知道他们什么时候会开始实施“smite”...
  • 哇,我真的没有意识到我的问题是如此愚蠢......对不起?......我现在会接受你的建议 Hamish。
  • 我不确定@Hamish Grubijan 在说什么,但你的问题并不愚蠢。我的猜测是,他是说 Perl 在这个网站上并不是一种受人尊敬的语言,但欢迎提出 Perl 问题 :)
  • @NiRC - 安定下来……Hamish 开了个有点失败的玩笑,Perl 上 98%,你身上 2%……就像“Perl 太糟糕/可怕,你应该在你被卷入更深之前停止尝试处理它”。
  • @Jim Lewis:七年前。 search.cpan.org/~ibb/Acme-Damn-0.02/Damn.pm Smite 不是别名之一,也许你应该提出请求。

标签: perl oop class bless


【解决方案1】:

在这种情况下,您对 $property 所做的操作被声明为“Person”包范围内的变量。您在包的内部(或使用 $Person::property 外部)更改它,并且引用它的任何对象都将看到更新的变量,因此它的行为很像没有任何 的“静态属性(Java)”真正的“私人”范围。按照惯例,Perl 中的隐藏内容(“private”或“protected”)都带有下划线前缀,但这当然不是强制的。

正如您所指出的,您实际上并没有使用“package”关键字创建一个新类;您完全可以在没有 OOP 的情况下使用“包”。这只是创建了一个单独的“命名空间”。

“祝福”一个变量的优势,从我所看到的几乎总是一个哈希引用,是你可以拥有方法,就像任何其他 OOP 语言一样。只要记住祝福你在 new {} 子例程中返回的任何内容(“new”实际上不是保留字;只是一个约定)。当您在“对象”(像 hashref 之类的受祝福的数据结构)上调用方法时,该方法的第一个参数是数据结构本身。所以,如果你有一个名为 $myobject 的 hashref,它被 AwesomeClass 所祝福,并且你在 AwesomeClass 中定义了一个名为 doSomethingAwesome 的方法,它需要接受一个变量,你将不得不“转移”@_(这是子例程,或使用 $_[0]) 访问 $myobject hashref。 Python 做了类似的事情,所有语言都以某种方式将对象引用传递给方法。 (许多中的“this”关键字,另见“thiscall”调用约定)

注意:在我作为程序员只有几年的时间里,我见过很多 Perl 抨击。 Perl 是一种非常棒的语言,它由一位非常聪明的语言学家(Larry Wall)创造,并拥有狂热的追随者——也许曾经比 Ruby 更狂热,但不如 David Koresh)。 Perl 做的事情与许多语言非常不同,但是如果你查看这个网站和其他网站上的代码高尔夫条目,你可以清楚地看到用很少的 Perl 就可以完成很多事情(不能保证代码的易读性,尤其是对于新手!)

【讨论】:

  • 非常感谢!我明白你现在在说什么了。 Perl 确实与我习惯的 C# 非常不同:)
  • 如果 David Koresh 和 Perl 一样,那么退出该死的化合物的方法不止一种!以及不止一个灭火剂模块。
【解决方案2】:

嗯,这不是您在 Perl 中创建类的方式。

您的 $property 变量在包范围内定义。因此,每个类只有一个副本,而不是每个对象都有自己的副本。

人们可能会使用基于哈希的对象来实现这样一个类,方法如下:

#!/usr/bin/perl

package Person;

use strict; use warnings;

sub new {
    my $class = shift;
    my $self = {};
    bless $self => $class;

    my ($arg) = @_;
    for my $property ( qw( message ) ) {
        if ( exists $arg->{$property} ) {
            $self->$property($arg->{$property});
        }
    }
    return $self;
}

sub message {
    my $self = shift;
    return $self->{message} unless @_;
    my ($msg) = @_;
    $self->{message} = $msg;
}

package main;

my $person = Person->new({
    message => "This is what I'm talking about :)"
});

print $person->message, "\n";

现在,这很快就会变得乏味。因此,有一些模块可以帮助您处理这个问题,并帮助您以安全的继承方式定义您的类。

Class::Accessor 就是这样一个实用模块。

对于启动时间不是问题的程序,您应该考虑Moose。使用 Moose,您可以将上述内容写为:

#!/usr/bin/perl

package Person;

use Moose;

has 'message' => (is => 'rw', isa => 'Str');

__PACKAGE__->meta->make_immutable;
no Moose;

package main;

my $person = Person->new({
    message => "This is what I'm talking about :)"
});

print $person->message, "\n";

您应该阅读perldoc perltootMoose::Manual::Unsweetened 了解标准的做事方式。

【讨论】:

  • 非常感谢这篇文章,非常有用的链接。我一直在使用 perldoc,但是很多文档都非常......至少可以说令人生畏:)
  • @NiRC - 我强烈建议阅读几本书(Perl 书籍上已经有一个 StackOverflow 问题,所以我不会费心推荐,除了通常的嫌疑人 - O'Reilly Perl系列)。恐怕 Perl 文档不一定是一个很好的学习材料(而不是在你过了最初的学习曲线后成为一个很好的参考材料)
  • @Sinan = Moose +1。和一个试用 -1 用于编写单独的 getter 和 setter,而不是统一的“如果没有参数,我是一个 getter”方法,ala 结果来自 Class::Accessor::Fast :)
  • 第二段显示它没有按预期工作。
  • @Ether:是的,但是使用术语“属性”强烈表明 OP 希望将数据与可以操作这些数据的代码相关联。
【解决方案3】:

呃……Sinan 的回答对我来说完全太博学了,至少在上午 12 点过去 :)

因此,为了多样化,我将给出一个更短且更少 Perly 的版本。

据我所知,您的问题与 Perl 无关,并且可以很容易地以另一种形式提出:“既然 C 已经有结构,为什么还要在其中使用 C++ 和 OOP? "

换句话说,您似乎在问使用 OOP 范式有什么意义。

答案当然是它比纯过程编程更容易解​​决某些软件工程问题。强调一定 - OOP 不是解决所有问题的灵丹妙药,任何技术/方法/范式都不是。

使用 OOP(在 Perl 中以包作为类的形式和作为对象的祝福哈希)允许您享受继承、多态性和其他您可能已经相当熟悉的 OOPyish mumbo-jumbo 非 Perl 的好处OOP 经验。

你能做到 100% 的事情,你可以用一个纯数据结构的祝福对象做到吗?绝对地。 100% 的代码会像使用对象实现的那样简单/简短/可读/可维护吗?很可能不会,尽管这取决于您的 OOP 代码实际上如何利用 OOP 提供的好处(顺便说一句,我已经遇到了所谓的 OOP 代码(Perl 和非 Perl),它并没有真正利用OOP 范式,如果去掉其 OOP chrome,本可以更容易阅读和理解)。

【讨论】:

  • 你还是太有学问了! :) IME、继承和多态性都是不错的选择,但 OOP 的真正好处在于它提供了一种将行为与数据关联起来的简洁而简单的方法。我的一些 OOP 项目使用多态性和继承。但它们都利用了数据和操作的清晰关联。与其查看复杂的多层结构和 27 个相关函数,我可以拥有 Foo 和 Bar 对象,它们包含在 nice Baz 对象中——根据需要在类之间划分 27 个方法。
【解决方案4】:

bless'ing 对象的值是使用特定包中的方法。

package MyClass;
sub answer { my ($self)=@_; return $self->{foo} * 42; }

package main;
my $object1 = { foo => 1, bar => "\t" };
my $object2 = bless { foo => 2, bar => "\t" }, "MyClass";

$ref1 = ref $object1;        #  'HASH'
$ref2 = ref $object2;        #  'MyClass'

$answer1 = $object1->answer;     # run time error
$answer2 = $object2->answer;     # calls MyClass::answer, returns 2 * 42 = 84

【讨论】:

    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 2014-01-19
    • 2010-09-28
    • 2014-07-29
    • 1970-01-01
    • 2011-11-14
    • 2014-01-17
    • 1970-01-01
    相关资源
    最近更新 更多