使用Perl和Moose
,可以通过两种方式访问对象数据。
$self->{attribute}
或$self->attribute()
这是一个简单的例子,展示了两者:
# 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()
版本,因为它可以防止你犯下愚蠢的错误并阻止你覆盖只读值,但是我的问题是......
Person.pm
的内部 是否最好使用
$self->{age}
或$self->age()
?覆盖模块本身 中的只读属性 是否被视为不良做法?如果希望更改其值,则将此属性更改为读/写属性,或者在{{1}中使用
$self->{age}
覆盖属性的只读方面是否可接受功能?
答案 0 :(得分:7)
使用Moose时,最佳做法是始终使用生成的访问器方法,即使在对象自己的类中也是如此。原因如下:
访问器方法可能被执行特殊操作的子类覆盖。调用$self->age()
可确保调用正确的方法。
可能会在属性中附加方法修饰符,例如before
或after
。直接访问哈希值将跳过这些。
可能有一个附加到属性的谓词或更清晰的方法(例如has_age
)。直接使用哈希值混淆会使它们混淆。
哈希键受拼写错误。如果您不小心说$self->{aeg}
,则不会立即发现该错误。但由于该方法不存在,$self->aeg
将会死亡。
一致性很好。没有理由在一个地方使用一种风格而在其他地方使用另一种风格。它使代码更易于理解。
在只读属性的特定情况下,以下是一些策略:
让您的对象真正不可变。如果需要更改值,请构造一个新对象,该对象是具有新值的旧对象的克隆。
使用只读属性存储实际年龄,并指定私有编写器方法
例如:
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 );
}
更新
以下是如何使用延迟构建器基于另一个属性设置一个属性的示例。
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
将存在。
直接设置哈希元素当然会跳过构建器方法。
答案 1 :(得分:4)
我不认为has 'weight' => (
is => 'ro',
writer => '_set_weight',
);
是一个记录在案的界面,所以它甚至不能保证有效。
在这种情况下,我使用https://metacpan.org/pod/Moose::Manual::Attributes#Accessor-methods中描述的私人作家:
'rwp'
您甚至可以使用https://metacpan.org/pod/MooseX::AttributeShortcuts#is-rwp中的use MooseX::AttributeShortcuts;
has 'weight' => (
is => 'rwp',
);
自动执行此操作:
for row in spamreader
答案 2 :(得分:1)
开箱即用的perl不是类型安全的,并且没有太多的封装方式,所以很容易做鲁莽的事情。穆斯在你的perl对象上施加了一些文明,为某些自由交换安全和稳定。如果穆斯太窒息了,那么潜在的Perl仍然存在,所以有办法解决穆斯铁拳试图放下的任何法律。
一旦你已经知道你已经宣布一个属性为只读,但你想要改变它,即使你还说你希望它是只读的,并且在大多数宇宙中你声明了一些东西只读,因为您不想更改它,然后一定要继续并更新$person->{age}
。毕竟,你知道自己在做什么。