Perl:在 Moose 类中添加编写器拒绝属性访问

Posted

技术标签:

【中文标题】Perl:在 Moose 类中添加编写器拒绝属性访问【英文标题】:Perl: Adding writer in Moose class denies attribute access 【发布时间】:2013-10-01 19:45:48 【问题描述】:

我刚开始学习 Moose,并且创建了一个非常基础的课程。这是我的代码:

Person.pm

package Person;

use Moose;

has fname => (
  is => 'rw',
  isa => 'Str',
  reader => 'getFirstName',
);

has lname => (
  is => 'rw',
  isa => 'Str',
  reader => 'getLastName',
  writer => 'setLastName',
);

sub printName 
  my $self = shift;
  print $self->getFirstName() . " " . $self->getLastName(), "\n";


no Moose;
__PACKAGE__->meta->make_immutable;

person.pl

#!/usr/bin/env perl

use strict;
use warnings;
use Person;

my $person = Person->new(fname => 'jef', lname => 'blah',);
print $person->fname, $person->lname, "\n";
$person->setLastName('bleh');
$person->getName();

这段代码死在第 8 行。它会打印出名字属性,但它会抱怨 lname Can't locate object method "lname" via package "Person" at ./person.pl line 8. 现在,如果我在 lname 中取出 writer,一切都很好,但这有什么意义呢?我意识到我可以使用我创建的 getter,但我很好奇为什么作家会拒绝我访问属性本身?我想我不明白一些东西......

【问题讨论】:

我冒昧地猜测一下,一旦定义了读取器和写入器,就不必直接访问该属性,因此拒绝访问;你应该可以写print $person->fname, $person->getLastName(), "\n"; 这有点令人困惑……文档中有吗? @incutonez: search.cpan.org/dist/Moose/lib/Moose/Manual/… @Axeman:啊,好的。感谢您指出了这一点。如果您包括在没有自定义 getter/setter 的情况下访问我的属性的正确方法(请参阅我对您的答案的评论),然后在此文档中提示我何时设置了自定义 getter/setter,那么我会接受您的回答。 【参考方案1】:

lname 不是“属性本身”,因为fname 也不是“属性本身”。它也是一个返回属性的函数。通过编写读者和作者,您选择您希望为这些子命名,仅此而已。

用错误的名字调用一个子会失败之前。当属性名称输入错误时,旧的 Perl OO 方法的祝福散列和成员字段作为散列键会导致可生存的运行时错误。为访问者制作 subs 背后的想法是尽早彻底地失败。由于散列可以存储任何字符串,因此受祝福的对象只能调用特定的一组函数,无论是为类定义的还是继承的。

根据the Manual,

每个属性都有一个或多个访问器方法。访问器允许您读取和写入对象的该属性的值。

默认情况下,访问器方法与属性同名。如果您将属性声明为 ro,那么您的访问器将是只读的。如果您将其声明为 rw,您将获得一个读写访问器。很简单。

鉴于上面的 Person 示例,我们现在有一个 first_name 访问器,可以读取或写入 Person 对象的 first_name 属性的值。

如果需要,您还可以显式指定用于读取和写入属性值的方法名称。当您希望某个属性可以公开读取但只能私下设置时,这特别方便。 [斜体我的]

【讨论】:

我对“也不是属性本身”感到困惑......这是否意味着我不应该像我一样打电话给fname?为什么突然添加一个作家会迫使我使用 getter/setter 而不是直接访问属性?这在文档中的某处有解释吗? $person->lname 实际上是 Moose 为您创建的组合读写器。属性本身存储在$person->'lname' 中。一旦您同时声明了读取器和写入器,Moose 就会决定您不再需要组合读取器/写入器,并且不会创建 lname 方法。 哇哦!这对我来说真的很愚蠢......所以我的 getter/setter 是默认设置的,它使用与我的属性相同的名称,所以如果我实际上没有设置自定义的 getter/setter 名称,我可以调用它通过$person->lname()$person->lname('bleh')。但是,当我设置自己的 getter/setter 时,这些就消失了。那很可爱。感谢您的帮助! @AKHolland 这应该是一个答案,而不是评论。

以上是关于Perl:在 Moose 类中添加编写器拒绝属性访问的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl/Moose 中,如何将修饰符应用于所有子类中的方法?

使用 Perl/Moose,修饰符返回的值会发生啥变化?

Moose 类属性类似于 Class::Data::Inheritable

你如何在 Perl 中创建对象?

使用Moose with Test :: Class - 构造函数的问题

为啥 Moose 代码这么慢?