Perl 如何在构建期间设置ro属性?

Perl 如何在构建期间设置ro属性?,perl,moose,Perl,Moose,我正在写一个剧本来帮助我精通驼鹿。我有以下代码: package Dir; use Moose; use Modern::Perl; use File; has 'dirs' => (is => 'ro', isa => 'HashRef[Dir]' ); has 'files' => (is => 'ro', isa => 'HashRef[File]'); has 'dir_class' =>

我正在写一个剧本来帮助我精通驼鹿。我有以下代码:

package Dir;
use Moose;
use Modern::Perl;
use File;

has 'dirs' =>             (is => 'ro', isa => 'HashRef[Dir]' );  
has 'files' =>            (is => 'ro', isa => 'HashRef[File]'); 
has 'dir_class' =>        (is => 'ro', isa => 'ClassName', default => 'Dir');
has 'file_class' =>       (is => 'ro', isa => 'ClassName', default => 'File');

sub BUILD {
  my $self = shift;
  my $path = $self->path;
  my $name = $self->name;
  my (%dirs, %files);

  # populate dirs attribute with LaborData::Data::Dir objects
  opendir my $dh, $path or die "Can't opendir '$path': $!";

  # Get files and dirs and separate them out
  my @dirs_and_files = grep { ! m{^\.$|^\.\.$} } readdir $dh;
  closedir $dh or die "Can't closedir '$path': $!";
  my @dir_names         = grep { -d "$path/$_" } grep { !m{^\.}  } @dirs_and_files;
  my @file_names        = grep { -f "$path/$_" } grep { !m{^\.}  } @dirs_and_files;

  # Create objects
  map { $dirs{$_}         = $self->dir_class->new  ( path => $path . '/' . $_ ) } @dir_names;
  map { $files{$_}        = $self->file_class->new ( path => $path . '/' . $_ ) } @file_names;

  # Set attributes
  $self->dirs         ( \%dirs );
  $self->files        ( \%files );
}
代码导致以下错误:
died:Moose::Exception::CannotAssignValueToReadOnlyAccessor(无法在reader Dir::dirs上将值分配给只读访问器)

为了避免这个错误,我可以对
dirs
文件
属性设置属性
rw
,或者使用
builder
方法。前一种解决方案是不可取的,后一种解决方案需要重复代码(例如,目录需要打开两次)这也是不可取的


这个问题的最佳解决方案是什么?

我找到了一个可能的解决方案,尽管人们不赞成:

  # Set attributes
  $self->{dirs}  =    \%dirs;
  $self->{files} =    \%files;
您可以指定只读属性,并从
构建中在内部使用该属性。使用
\uuu
命名该属性以指示其为内部属性

package Foo;
use Moose;

has bar => ( is => 'ro', writer => '_set_bar' );

sub BUILD {
    my $self = shift;

    $self->_set_bar('foobar');
}

package main;
Foo->new;
这不会引发异常


它本质上与使其成为
rw
相同,但现在编写者与读取器不是同一个访问器。
\u
表明它是内部的,因此它比仅仅使用
rw
更不受欢迎。请记住,无论如何,您不能真正保护Perl中的任何内容。如果您的用户想要访问内部,他们会这样做。

不要那样做。如果你想学驼鹿,不要弄乱它的内部结构。我想知道
StevensPerlTools
do.:)好的,非常感谢。这似乎是实现这一点的最佳方法。@simbabque:那么每个
ro
属性都必须被赋予
writer
,否则它将永远处于未初始化状态?另外,请解释一下你上面的笑话,因为我今晚显得特别笨。@Borodin过去有一个
使用StevesPerlTools行。@Borodin通常通过构造函数初始化
ro
属性<代码>Foo->new(条形图=>123)将设置它。这里的要点是一些属性是在
BUILD
期间构造的,这发生在对象构造之后(
BUILDARGS
之前)。因此,如果其中一些属性没有传入(可能是故意的、偶然的,也可能是因为您删除了
init_arg
),并且您仍然希望设置它们,那么您可以为属性添加一个
writer
。而
\uuu
表示其他人应该远离。请参见笑话问题的编辑历史记录。:)@Borodin可以通过构造函数(
Foo->new(bar=>42)
)使用
默认值或
builder
方法初始化
ro
属性。如果这些都不适用,则该属性将被删除。如果没有私人的
编写器
,是的,它将永远保持这种状态。