拥有下一个包
package MyTest;
use warnings;
use Moose;
use Types::Path::Tiny qw(AbsPath AbsFile);
has 'file' => (
is => 'ro',
isa => AbsPath,
required => 1,
coerce => 1,
);
no Moose;
__PACKAGE__->meta->make_immutable;
1;
工作(差不多),所以使用时
use strict;
use warnings;
use feature 'say';
use Mytest;
use DDP;
my $t1 = MyTest->new(file => './t'); # the ./t is existing file in the filesystem
say $t1 ? "ok" : "no";
my $t2 = MyTest->new(file => './nonexistent_file');
say $t2 ? "ok" : "no";
p $t2;
说" ok"对彼此而言。而$t2->file
是isa "Path::Tiny
但是,如果文件系统中确实存在该文件,我不想创建该对象。因此,第二个($t2
)调用应该返回undef
。
更改
isa => AbsPath,
到
isa => AbsFile,
将检查文件的存在,但如果它不存在 - 脚本将死于
Attribute (file) does not pass the type constraint because: File '/tmp/nonexistent_file' does not exist
我不想死,只想创建MyTest
实例,如果文件不存在则返回undef,或者它不是普通文件。如果文件存在,则该文件应为Path::Tiny
实例。 (从Str强迫)。
有人能帮助我吗?
答案 0 :(得分:3)
最简单的方法是捕获并丢弃预期的错误:
use Try::Tiny;
my $instance = try {
MyTest->new(file => './nonexistent_file');
} catch {
# only mute the constraint errors
return undef if /\AAttribute [(]\w+[)] does not pass the type constraint/;
die $_; # rethrow other errors
};
使用构造函数进行处理,以便在失败时返回undef
并不是一个好主意,因为有一个隐含的契约->new
将始终返回有效的实例。在较旧的Perl代码中,在失败时返回特殊值被认为是正常的,但这会强制对调用者进行额外检查 - 并且可能会忘记检查。通过使用exeptions(因此强制它们被处理),Moose采取了更强大的路线,尽管在这种特定情况下,这确实增加了一些样板。
如果要隐藏此样板,请考虑编写工厂方法。
答案 1 :(得分:2)
我评论@ amon的帖子,但改变了我的想法,因为他的解决方案是普遍的,我的只处理这个特殊情况,无论如何发布它:
my $file = './nonexistent_file';
my $t2 = (-f $file) ? MyTest->new(file => $file) : undef;