gpt4 book ai didi

Perl 驼鹿 : Attribute only getting set when mentioned in BUILD subroutine

转载 作者:行者123 更新时间:2023-12-02 08:15:51 24 4
gpt4 key购买 nike

我正在构建一个脚本,该脚本以递归方式构建目录的子目录/文件的名称以及这些子目录中的文件的名称作为对象:

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

has 'path' => (is => 'ro', isa => 'Str', required => 1);
has 'name' => (is => 'ro', isa => 'Str', lazy => 1, default => sub { my $self = shift; my ($name) = $self->path =~ /\/([^\/]*)$/; return $name; } );
has 'subdirs' => (is => 'rw', isa => 'ArrayRef[Dir]' );
has 'files' => (is => 'rw', isa => 'ArrayRef[File]' );
has 'num_dirs' => (is => 'ro', isa => 'Int', lazy => 1, default => sub { my $self = shift; scalar @{$self->subdirs}; } );


sub BUILD {
my $self = shift;
my $path = $self->path;

# run some tests
logf('Path to the directory does not exist.') if (!-e $path);
logf('The path should point to a directory, not a file.') if (!-d $path);

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

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

# Create objects
my @dir_objects = map { Dir->new ( path => $path . '/' . $_ ) } @subdir_names;
my @file_objects = map { File->new ( path => $path . '/' . $_ ) } @file_names;

# Populate this with file and directory objects
$self->subdirs ( \@dir_objects );
$self->files ( \@file_objects );
}

1;

注意代码有一个 files 属性,它包含一个 File 对象数组。 File 具有以下属性:

has 'path' => (is => 'ro', isa => 'Str', required => 1); 
has 'name' => (is => 'ro', isa => 'Str', lazy => 1, default => sub { my $self = shift; my ($name) = $self->path =~ /\/([^\/]*)$/; return $name; } );

问题是 name 属性在创建 File 对象时永远不会被设置。我不确定为什么。

编辑 1:解决方案(某种程度上)因此,我将其放入 File 对象中以查看它是否触发了属性的创建:

sub BUILD {
my $self = shift;
}

这并没有解决问题。然而,这确实:

sub BUILD {
my $self = shift;
$self->name;
}

不过,我的问题是为什么我需要这样做?

最佳答案

问题是如果有尾部斜杠,您的模式就会失败。

my ($name) = $self->path =~ /\/([^\/]*)$/;

如果 $self->path/some/thing 它会起作用。如果它是 /some/thing/ 它“有效”但是 [^\/]* 很乐意匹配一个空字符串。所以你不会收到任何警告。

您可以输入一个可选的斜杠,并更改它以匹配一个或多个非斜杠。此外,通过使用替代分隔符,我们可以清理所有那些倾斜的牙签。

my ($name) = $self->path =~ m{/ ([^/]+) /? $}x;

但实际上不应该使用正则表达式来解析路径。使用许多内置模块之一,如 File::BasenameFile::Spec

return basename($self->path);

一些旁注。

Moose 启动速度非常慢,最适合长时间运行的进程,如网络服务器。对于像 File 和 Dir 类这样通用的东西,考虑使用 Moo .它主要与 Moose 兼容,速度更快,并且与 Types::Standard 结合使用时, 类型更好。例如,最好创建一个 StrNotEmpty 类型来避免此类问题。

除非这是一个练习,否则 Perl 已经有一个很棒的模块来做这类事情。查看Path::Tiny .

关于Perl 驼鹿 : Attribute only getting set when mentioned in BUILD subroutine,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42035292/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com