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
属性。如果这些都不适用,则该属性将被删除。如果没有私人的编写器
,是的,它将永远保持这种状态。