【问题标题】:Moose: change read-write attributes to read-only after constructing the objectMoose:构造对象后将读写属性改为只读
【发布时间】:2018-09-10 19:47:07
【问题描述】:

我想在调用 BUILD 方法后将对象的属性更改为只读。我该怎么做?

(上下文:我的程序使用MooseX::YAML从YAML加载这个我想在创建后刻在石头上的对象,然后在BUILD方法中更改它的属性,以解决YAML的限制描述here。更具体地说,我的 YAML 代码声明了一个目录和它下面的一堆文件,但似乎没有办法在 YAML 中表示所有这些文件都必须在该目录中。当然,我可以预先添加这个目录名到所有这些文件名,使它们成为绝对的,但这意味着 1) 当我改变对目录位置的想法时,我必须更改这些文件的所有条目,而不是只更改目录名,并且2)在创建对象之前从程序内部更改目录名称会很痛苦并且容易出错。)

(稍后添加:)一个最小的工作示例。

yaml1:

# invalid YAML, unfortunately:
dir: &dir /here
file1: *dir/foo
file2: *dir/bar
# ... and a lot more

yaml2:

# works, but requires repeating '/here/':
dir: /here
file1: /here/foo
file2: /here/bar
# ...

yaml3:

# works, but requires making changes to attribute values:
dir: /here
file1: foo
file2: bar
# ...

program.perl:

use strict;
use warnings;
use lib '.';
use MooseX::YAML qw (LoadFile);
use Try::Tiny;

foreach (1..3) {
  my $datafile = "yaml$_";
  print STDERR "Loading $datafile...\n";
  try {
    LoadFile ("yaml$_");
  } catch {
    print STDERR "$_";
  };
}

在一个目录中创建所有这些文件并从那里运行“perl program.perl”,我得到以下输出:

Loading yaml1...
YAML::XS::Load Error: The problem:

    did not find expected alphabetic or numeric character

was found at document: 1, line: 2, column: 12
while scanning an alias at line: 2, column: 8
Loading yaml2...
Loading yaml3...

“mypkg.pm”文件显示了我在使用 yaml3 时必须对属性进行的更改。

mypkg.pm:

package mypkg;
use Moose;
use File::Spec;

has 'dir' => (isa => 'Str', is => 'ro');
# have to allow modifying these values in BUILD
#                                              (!!)
has [qw (file1 file2)] => (isa => 'Str', is => 'rw');

sub BUILD {
  my ($self) = @_;
  $self->file1 (File::Spec->catfile ($self->dir, $self->file1));
  $self->file2 (File::Spec->catfile ($self->dir, $self->file2));
  # ... etc.
  # everything done, I would like all further changes to the attribute 
  # values to be impossible from now on
}

__PACKAGE__->meta->make_immutable;

【问题讨论】:

    标签: perl moose


    【解决方案1】:

    这是一种可以写入BUILD() 子中的只读属性的方法:

    package mypkg;
    use Moose;
    use File::Spec;
    
    has [qw (file1 file2)] => (isa => 'Str', is => 'ro');
    has dir => (isa => 'Str', is => 'ro');
    
    sub BUILD {
        my ($self) = @_;
        # Note that we use $self->{file1} instead of $self->file1 in order to 
        # fool Moose and write to its read-only attributes
        $self->{file1} = File::Spec->catfile($self->dir, $self->file1);
        $self->{file2}  = File::Spec->catfile($self->dir, $self->file2);
    }
    

    另见Writing to read-only attributes inside a Perl Moose class

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-02
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      • 2016-02-25
      • 1970-01-01
      • 2012-05-15
      相关资源
      最近更新 更多