$self-> {attribute}或$self->属性()
这是一个简单的例子,展示了两者:
# 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()版本,因为它可以防止你犯下愚蠢的错误并阻止你覆盖只读值,但我的问题是…
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?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 theHAPPY_BIRTHDAY
function?
解决方法
>访问器方法可能被执行特殊操作的子类覆盖.调用$self-> age()可确保调用正确的方法.
>可能有附加到属性的方法修饰符,例如之前或之后.直接访问哈希值将跳过这些.
>可能有一个附加到属性的谓词或更清晰的方法(例如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',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 }
在访问年龄之前不会调用惰性构建器,因此您可以确定is_baby将存在.
直接设置哈希元素当然会跳过构建器方法.