如何在构建过程中设置 ro 属性?
How to set ro attributes during build?
我正在编写一个脚本来帮助我精通 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' => (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 (Cannot assign a value to a read-only accessor at reader Dir::dirs
为了解决这个错误,我可以为 dirs
和 files
属性创建属性 rw
或使用 builder
方法。前一种方案不可取,后一种方案需要重复代码(比如目录需要打开两次),同样不可取。
这个问题的最佳解决方案是什么?
我找到了一个可能的解决方案,尽管它不受欢迎:
# Set attributes
$self->{dirs} = \%dirs;
$self->{files} = \%files;
您可以将 a writer
分配给您的 read-only 属性并在您的 BUILD
内部使用它。用 _
命名它以表明它是内部的。
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
本质上是一样的,但现在编写器与reader不是同一个访问器。 _
表示它是内部的,因此它比仅使用 rw
更不受欢迎。请记住,无论如何您都无法真正保护 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' => (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 (Cannot assign a value to a read-only accessor at reader Dir::dirs
为了解决这个错误,我可以为 dirs
和 files
属性创建属性 rw
或使用 builder
方法。前一种方案不可取,后一种方案需要重复代码(比如目录需要打开两次),同样不可取。
这个问题的最佳解决方案是什么?
我找到了一个可能的解决方案,尽管它不受欢迎:
# Set attributes
$self->{dirs} = \%dirs;
$self->{files} = \%files;
您可以将 a writer
分配给您的 read-only 属性并在您的 BUILD
内部使用它。用 _
命名它以表明它是内部的。
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
本质上是一样的,但现在编写器与reader不是同一个访问器。 _
表示它是内部的,因此它比仅使用 rw
更不受欢迎。请记住,无论如何您都无法真正保护 Perl 中的任何内容。如果您的用户想要了解内部结构,他们会的。