Perl中的布尔函数应该返回什么值?

时间:2016-09-17 00:46:48

标签: perl boolean undef

简短问题

在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)。

1 个答案:

答案 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的任何标量值,并且有任何方法可以在列表上下文中调用你的子程序(甚至意外),那么你已经在你的代码中引入了一个潜在的错误。

单独一点,在打印它们之前必须解码布尔值是非常值得的。