在 Perl Moose 类中写入只读属性 [英] Writing to read-only attributes inside a Perl Moose class
问题描述
使用 Perl 和 Moose
,可以通过两种方式访问对象数据.
Using Perl and Moose
, object data can be accessed in 2 ways.
$self->{attribute}
或 $self->attribute()
这是一个简单的例子来演示两者:
Here is a simple example demonstrating both:
# Person.pm
package Person;
use strict;
use warnings;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'age' => (is => 'ro', isa => 'Int');
sub HAPPY_BIRTHDAY {
my $self = shift;
$self->{age}++; # Age is accessed through method 1
}
sub HAPPY_BIRTHDAY2 {
my $self = shift;
my $age = $self->age();
$self->age($age + 1); # Age is accessed through method 2 (this will fail)
}
1;
# test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Person;
my $person = Person->new(
name => 'Joe',
age => 23,
);
print $person->age()."\n";
$person->HAPPY_BIRTHDAY();
print $person->age()."\n";
$person->HAPPY_BIRTHDAY2();
print $person->age()."\n";
我知道当您在 Person.pm
文件之外时,最好使用 $person->age()
版本,因为它会阻止您犯愚蠢的错误,会阻止你覆盖只读值,但我的问题是......
I know that when you are outside of the Person.pm
file it is better to use the $person->age()
version since it prevents you from making dumb mistakes and will stop you from overwriting a read only value, but my question is...
Inside Person.pm
最好使用 $self->{age}
或$self->age()
?覆盖模块本身中的只读属性是否被认为是不好的做法?
Inside of
Person.pm
is it best to use$self->{age}
or$self->age()
? Is it considered bad practice to overwrite a read-only attribute within the module itself?
如果该属性的值预计会发生变化,是否应将该属性更改为读/写属性,或者是否可以使用 $self->{age 覆盖属性的只读方面?}
在 HAPPY_BIRTHDAY
函数内?
Should this attribute be changed to a read/write attribute if its value is ever expected to change, or is it considered acceptable to override the read-only aspect of the attribute by using $self->{age}
within the HAPPY_BIRTHDAY
function?
推荐答案
使用 Moose 时,最佳实践是始终使用生成的访问器方法,即使在对象自己的类中也是如此.以下是几个原因:
When using Moose, the best practice is to always use the generated accessor methods, even when inside the object's own class. Here are a few reasons:
访问器方法可能会被执行特殊操作的子类覆盖.调用
$self->age()
可确保调用正确的方法.
The accessor methods may be over-ridden by a child class that does something special. Calling
$self->age()
assures that the correct method will be called.
可能有方法修饰符,例如 before
或 after
,附加到属性上.直接访问哈希值将跳过这些.
There may be method modifiers, such as before
or after
, attached to the attribute. Accessing the hash value directly will skip these.
可能有附加到属性的谓词或更清晰的方法(例如 has_age
).直接弄乱哈希值会混淆它们.
There may be a predicate or clearer method attached to the attribute (e.g. has_age
). Messing with the hash value directly will confuse them.
哈希键可能会出现拼写错误.如果你不小心说 $self->{aeg}
错误不会立即被发现.但是 $self->aeg
会死,因为该方法不存在.
Hash keys are subject to typos. If you accidentally say $self->{aeg}
the bug will not be caught right away. But $self->aeg
will die since the method does not exist.
一致性很好.没有理由在一个地方使用一种风格而在其他地方使用另一种风格.它也让新手更容易理解代码.
Consistency is good. There's no reason to use one style in one place and another style elsewhere. It makes the code easier to understand for newbs as well.
在只读属性的特定情况下,这里有一些策略:
In the specific case of a read-only attribute, here are some strategies:
让你的对象真正不可变.如果需要更改值,请构造一个新对象,该对象是具有新值的旧对象的克隆.
Make your objects truly immutable. If you need to change a value, construct a new object which is a clone of the old one with the new value.
使用只读属性存储真实年龄,并指定私有写入方法
Use a read-only attribute to store the real age, and specify a private writer method
例如:
package Person;
use Moose;
has age => ( is => 'ro', isa => 'Int', writer => '_set_age' );
sub HAPPY_BIRTHDAY {
my $self = shift;
$self->_set_age( $self->age + 1 );
}
更新
这里有一个示例,说明如何使用惰性构建器根据另一个属性设置一个属性.
Here's an example of how you might use a lazy builder to set one attribute based on another.
package Person;
use Moose;
has age => ( is => 'rw', isa => 'Int', lazy => 1, builder => '_build_age' );
has is_baby => ( is => 'rw', isa => 'Bool', required => 1 );
sub _build_age {
my $self = shift;
return $self->is_baby ? 1 : 52
}
在访问 age
之前不会调用惰性构建器,因此您可以确定 is_baby
将在那里.
The lazy builder is not called until age
is accessed, so you can be sure that is_baby
will be there.
直接设置hash元素当然会跳过builder方法.
Setting the hash element directly will of course skip the builder method.
这篇关于在 Perl Moose 类中写入只读属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!