简短问题
在 Perl 代码库中一致地表示真假的最佳方法是什么?
1
/0
? 1
/Perl 原生 boolean 运算符的特殊空字符串返回?
undef
? ()
(即空列表)? 问题背景
我们都知道 Perl 在 boolean 值方面非常灵活,就像大多数事情一样。
例如,Perl 将以下内容视为错误:
undef()
,号码0
(即使写成 000 或 0.0),一个空字符串,'0'
(包含单个 0 数字的字符串)。 Perl 将以下情况视为真:任何其他标量值,1
, -1
, 一个带有空格的字符串 ( ' '
), '00'
字符串中有多个 0,"0\n"
('0' 后跟换行符),'true'
, 'false'
, 'undef'
等。此外,数组到标量和列表到标量的转换意味着您经常可以使用空数组作为假值。 (归功于 http://perlmaven.com/boolean-values-in-perl 用于 Perl 接受为真或假的标量值的部分列表。)但是考虑到所有这些被视为真或假的值,Perl boolean 函数应该返回什么?
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>>
当您自己编写 boolean 函数时,从 Perl 中的 boolean 函数返回值的最著名方法是什么?
也许您希望您的代码类似于 Perl,可以替代 Perl 现有的 boolean 运算符。或者您可能想要像 1/0 这样的数值。或者你可能来自 LISP,并期待 Perl 的
undef
用于 LISP 的 nil
为假(但随后您会发现 Perl 将许多其他值隐式处理为假)。
最佳答案
我为 boolean 真值返回 1。我真的看不出来 !!1
增加除了困惑之外的任何东西。
但我通常不会为 boolean 假值返回任何内容。那是因为裸 return
将根据子例程的调用方式返回适当的值。 return
的文档说这个:
If no EXPR is given, returns an empty list in list context, the undefined value in scalar context, and (of course) nothing at all in void context.
这很重要,因为 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;
}
}
一切都会按预期进行。如果您的子程序在标量上下文中被调用,它将返回一个标量假值,如果它在列表上下文中被调用,它将返回一个空列表。
在我看来,从子程序返回显式错误标量值总是值得怀疑的。
如果您想返回一个明确的标量假值,那么检查调用上下文并在错误时采取适当的措施是非常值得的。
croak 'Subroutine called in list context.' if wantarray;
更新:来回答这个评论。
IIRC I tried using this approach, but gave up on it because it produced more warnings about undefined values - i.e. it was not a drop-in replacement for an existing Perl 1/!!0 comparisons, nor for 1/0. Consider
perl -wle 'print "a()=<<".a().">>\n"; sub a {if(@_) {return 1} else {return}} '
, versusreturn !!@_
boolean 值的作用是您可以询问它是真还是假。就这些。在我看来,你不应该期望能够只打印一个 boolean 值。您经常可以在不触发警告的情况下打印 boolean 值这一事实很好,但不应依赖。如果我想打印一个 boolean 值,我总是会使用某种逻辑检查(可能是三元运算符)来完成它。所以我会像这样写你的例子:
$ perl -wle 'print "a()=<<".(a() ? "True" : "False").">>\n"; sub a {if(@_) {return 1} else {return}}'
我只是重申我原来的观点。如果您返回 false 的任何标量值,并且可以通过任何方式在列表上下文中调用您的子例程(即使是意外),那么您已经在代码中引入了一个潜在的错误。
仅此一项,就值得在打印 boolean 值之前对其进行解码的微不足道的痛苦。
关于perl - Perl 中的 boolean 函数应该返回什么值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39541833/