在 Perl Moose 类中写入只读属性 [英] Writing to read-only attributes inside a Perl Moose class

查看:52
本文介绍了在 Perl Moose 类中写入只读属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 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:

  1. 访问器方法可能会被执行特殊操作的子类覆盖.调用 $self->age() 可确保调用正确的方法.

  1. 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.

可能有方法修饰符,例如 beforeafter,附加到属性上.直接访问哈希值将跳过这些.

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:

  1. 让你的对象真正不可变.如果需要更改值,请构造一个新对象,该对象是具有新值的旧对象的克隆.

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆