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 中,如何将修饰符应用于所有子类中的方法?
Moose 类属性类似于 Class::Data::Inheritable