简短问题
在Perl代码库中一致表示true和false的最佳方法是什么?
1
/ 0
?
1
/ Perl的本机布尔运算符
的特殊空字符串
返回?
undef
()
(即空列表)?
问题背景
我们都知道Perl在布尔方面非常灵活,就像大多数事情一样。
例如,Perl将以下内容视为false:undef()
,数字0
(即使写为000或0.0),空字符串'0'
(包含a的字符串)单个0位数)。 Perl将以下内容视为true:任何其他标量值1
,-1
,其中包含空格的字符串(' '
),'00'
字符串中的多个0, "0\n"
(' 0'后跟换行符),'true'
,'false'
,'undef'
等。另外,数组到标量和列表-to-scalar转换意味着您通常可以使用空数组作为假值。 (感谢http://perlmaven.com/boolean-values-in-perl获取Perl接受为真或假的标量值的部分列表。)
但是考虑到所有这些被视为true或false的值,Perl布尔函数应该返回什么?
1/0
-1/0
(不)1/undef
1/""
如果您使用这些约定中的任何一个,您将很快发现您编写的代码的行为与普通的Perl代码不同。您将无法将$a<$b
替换为custom_less_than($a,$b)
,并使其工作完全相同。
考虑:
> perl -e 'use warnings;
sub my_eq { return ( $_[0]==$_[1] ? 1 : 0 ) }
print "compare (1==0) <<".(1==0).">>"
." to my_eq(1,0) <<".my_eq(1,0).">>"
."\n" ;'
Output:
compare (1==0) <<>> to my_eq(1,0) <<0>>
当你自己编写Perl中的布尔函数时,返回值的最有名的方法是什么?
也许您希望您的代码类似于Perl,可能替代Perl现有的布尔运算符。或许您想要数字值,如1/0。或许你来自LISP,并希望Perl的undef
被用作LISP的nil
是假的(但是那时你会绊倒Perl对许多其他人的隐含处理值为false)。
答案 0 :(得分:6)
我返回1表示布尔值true。我无法真正看到!!1
除了混淆之外还添加任何其他内容。
但我通常不返回布尔值false。这是因为裸return
将返回适当的值,具体取决于子程序的调用方式。 return
的文档说明了这一点:
如果没有给出EXPR,则返回列表上下文中的空列表,标量上下文中的未定义值,以及(当然)void上下文中没有任何内容。
这很重要,因为在标量和列表上下文之间,true和false值可能会有微妙的差别。想象一下像这样的子程序:
sub some_boolean {
if ($some_condition) {
return 1;
else {
return undef; # same effect with any scalar value
}
}
如果在标量上下文中调用它,则可以正常工作。
if (some_boolean()) {
...
} else {
...
}
一切按预期工作。但如果你在列表上下文中调用它,事情会有点奇怪。
my @array = some_boolean();
if (@array) {
...
} else {
...
}
在这种情况下,永远不会调用else
块。在列表上下文中,子例程返回包含单个标量的列表(值undef
),因此@array
具有单个元素,if (@array)
测试始终为真。
当然,您的子程序并不意味着在列表上下文中调用。但是你无法控制其他程序员如何使用你的代码。
但如果子程序是这样写的:
sub some_boolean {
if ($some_condition) {
return 1;
} else {
return;
}
}
一切都会按预期工作。如果在标量上下文中调用子例程,它将返回标量false值,如果在列表上下文中调用它,它将返回一个空列表。
在我看来,从子程序中返回一个显式的伪标量值总是令人怀疑。
如果你想返回一个明确的标量假值,那么非常值得检查调用上下文并在错误的情况下采取适当的行动。
croak 'Subroutine called in list context.' if wantarray;
更新:回答此评论。
IIRC我尝试使用这种方法,但放弃了它,因为它产生了更多关于未定义值的警告 - 即它不是现有Perl 1 / !! 0比较的替代品,也不是1/0。考虑perl -wle 'print "a()=<<".a().">>\n"; sub a {if(@_) {return 1} else {return}} '
,而不是return !!@_
布尔值的作用是您可以询问它是真还是假。就这些。在我看来,你不应该期望能够只打印一个布尔值。您经常可以在不触发警告的情况下打印布尔值的事实很好,但是不应该依赖它。如果我想打印一个布尔值,我总是会使用某种逻辑检查(可能是三元运算符)来完成它。所以我写这样的例子:
$ perl -wle 'print "a()=<<".(a() ? "True" : "False").">>\n"; sub a {if(@_) {return 1} else {return}}'
我只是重申我原来的观点。如果你返回false的任何标量值,并且有任何方法可以在列表上下文中调用你的子程序(甚至意外),那么你已经在你的代码中引入了一个潜在的错误。
单独一点,在打印它们之前必须解码布尔值是非常值得的。