我宁愿这样做:
say $shop->ShopperDueDate->andand->day_name();
VS。这样:
say $shop->ShopperDueDate->day_name() if $shop->ShopperDueDate;
有什么想法吗?
(这个想法的灵感来自Ruby andand扩展。)
(实际上它的灵感来自Groovy语言,但大多数人都不知道; - )
更新:我认为may()和eval {}都是很好的解决方案。这不是ruby,所以我不能期望从左到右阅读所有的方法/功能,所以也许肯定会有所帮助。当然,eval确实是实现它的perl方式。
答案 0 :(得分:9)
您可以使用Perl的eval
语句来捕获异常,包括尝试在未定义的参数上调用方法的异常:
eval {
say $shop->ShopperDueDate->day_name();
};
由于eval
返回最后评估的语句,或者undef
失败,您可以将日期名称记录在变量中,如下所示:
my $day_name = eval { $shop->ShopperDueDate->day_name(); };
如果您确实希望检查异常,可以查看特殊变量$@
。对于Perl的内置异常,这通常是一个简单的字符串,但如果异常来自autodie或其他使用对象异常的代码,则可能是完整的异常对象。
eval {
say $shop->ShopperDueDate->day_name();
};
if ($@) {
say "The error was: $@";
}
也可以使用eval
块将一系列命令串在一起。以下内容仅检查是否为周末,前提是我们在查找$day_name
时没有任何例外情况。
eval {
my $day_name = $shop->ShopperDueDate->day_name();
if ($day_name ~~ [ 'Saturday', 'Sunday' ] ) {
say "I like weekends";
}
};
您可以将eval
视为与其他语言的try
相同;实际上,如果你使用的是CPAN中的Error模块,那么你甚至可以拼写它try
。值得注意的是,eval的块形式(我上面已经演示过)并没有性能损失,并且与其他代码一起编译。 eval
的字符串形式(我没有显示)完全是一个不同的野兽,如果有的话应该谨慎使用。
eval
在技术上被认为是Perl中的一个语句,因此是少数几个在块结尾处看到分号的地方之一。如果您不定期使用eval
,很容易忘记这些。
保
答案 1 :(得分:9)
我认为你的第二个例子最好是:
say $shop->ShopperDueDate ? $shop->ShopperDueDate->day_name() : undef;
而不是它实际上说的。
无论如何,如果没有源过滤器,完全那个语法就不能这样做,因为undef
不是一个对象,而是一元运算符,所以它不能有任何方法
相反,请考虑一下:
package noop;
our $maybe = bless [], 'noop';
sub AUTOLOAD { undef };
这个$noop::maybe
是一个对象;它的所有方法都返回undef
。在其他地方,你将有这样的常规功能:
sub maybe { $_[0] || $noop::maybe; }
然后你可以这样写:
say maybe($shop->ShopperDueDate)->day_name()
这是因为“maybe”返回如果为true则返回其参数,否则返回我们的$noop::maybe
对象,该对象具有始终返回undef的方法。
编辑:更正! ->andand->
语法 可以在没有源过滤器的情况下使用XS来解决Perl的内部问题。 Leon Timmermans做了一个采用这条路线的实现。它全局替换undef()
函数,因此它可能比我的方法慢很多。
答案 2 :(得分:4)
我想我刚写完了。我刚刚将其上传到CPAN,您可以找到它here。
答案 3 :(得分:0)
像(未经测试)的东西:
use Object::Generic::False;
sub UNIVERSAL::andand { $_[0] || Object::Generic::False->false }
UNIVERSAL自动成为所有其他类的子类,因此这为所有对象提供了和。 (显然,在UNIVERSAL中创建方法有可能在远处发生冲突或令人惊讶的行为, 因此不应该不小心使用它。)如果调用andand方法的对象为true,则返回它; 否则返回一个泛型false对象,该对象为其上使用的任何方法调用返回自身。