---+简短回答
以下是 Perl 中布尔值的两个自洽方案:
-
1/0 - 可打印和便携
-
1/!!0 - 最像 Perl 的原生布尔函数
1/0可能是其他语言的程序员最熟悉的,比如 C 或 Python。您可以打印1/0 布尔值、添加它们等等。但是... Perl 的原生布尔运算符不是 1/0 值,return $a<0 与 return 1 if $a<0; return 0 不同。
1/0!! 是我尝试为 Perl 的本机布尔运算符使用的方案创建一个缩写名称:1 表示真,一个空字符串,经过特殊标记,以便在用于算术或插入字符串时不会产生警告. !!0 是产生这个特殊的 Perl 假值的最简单的方法之一,并且应该为使用 C 等许多语言的程序员所熟悉,作为标准化布尔值的一种方式。您可以添加1/0!!,也可以打印1/0 布尔值,只要您不在乎假值是否不可见,即空字符串。
避免意外在同一个函数或库中混合数字 1/0、Perl 的本机条件、undef 和其他方案。
故意混用时,使用转换运算符如
-
!!$bool_0or1 转换为传统的 1/!!0Perl 值
-
(0+($a<0)) 将 Perl 关系结果转换为 1/0
(!!any_other_boolean())
(0+any_other_boolean())
-
($other_bool?1:()) 从其他布尔方案转换为 1/()
-
($other_bool?1:undef) 从其他布尔方案转换为 1/undef
问:除了?:,还有其他更短或类似前缀的符号吗?
还有一些可能的方案
-
1/() - 更准确地说,返回 1 或不返回 - 可以捕获
一些 Perl-ish 错误,例如返回布尔标量 false,如 0 或
undef 在列表上下文中,它将变为 true
-
(1)/(0) - 返回一个包含 1 的长度为 1 的列表,或者一个空的
列表。类似于1/(),在真实和
false 是数组。
-
1/undef - 另一种可能性,捕获 1/() return 1 的错误
或者没有可能导致
我不愿推荐这些。至少,1/() 是不一致的,但是……它们肯定已经被 Perl 程序员使用,所以你应该准备好处理使用这些方案的代码。 IE。准备调试由这些方案引起的错误。
1/() 是我尝试为返回 true 的函数 return 1; 和返回 false 的函数执行 return; 的方案创建缩写名称,即没有操作数值的返回。 IE。 返回 1 或不返回任何内容。我相信 return nothing 等同于return ();。此方案可保护您免受程序员在列表上下文而不是标量上下文中评估您的函数引起的错误。但它会使您暴露于诸如{1=>return_nothing_if_false(),2=>return_nothing_if_false()} 之类的错误(因为您可能不想要{1=>2}。
顺便说一句,我认为执行(1)/() 的方案可能更一致。这将使您能够始终如一地拥有这种布尔类型的变量,当然是@array 变量。
请注意,1/undef 不等同于上述任何一个。 1/undef 布尔变量在 false=undef 被打印或插值或在算术中使用时发出警告,但当 true=1 被如此操作并在列表上下文中评估为 true 时不会发出警告。有人可能会说它具有所有方案中最差的特性。
对于1/()、(1)/() 或 1/undef 的这些方案,我犹豫不决。至少,1/() 是不一致的
所有这三个方案1/()、(1)/() 或 1/undef 都会将您暴露在诸如 {1=>f1_return_nothing_if_false(),2=>f2_return_nothing_if_false()} 之类的错误中,因为如果两者都为假,您可能不希望 {a=>"b"} 和 {a=>1,b=>1} 如果两者都为假是真的。至少如果 f1 返回 true 而 f2 返回 false,或者反之亦然,您将收到关于奇数大小哈希的警告。
调用函数的程序员可以控制是否在列表或标量上下文中计算它,但她可能无法控制它是否返回真或假。
恕我直言,如果您使用 1/()、(1)/() 或 1/undef,则无法在数组上下文中安全地调用此类函数,例如构建关键字参数 foo(kw=>boolfunc(),...) 或 foo({kw=>boolfunc(),kw2=>...},...)。不必分散!或全部为 0+。
---+中等长度答案
概括原始答案:
Perl 有多种表示真理的方式。或者更确切地说,Perl 将许多不同的值解释为真或假。
如果您要创建一系列相关函数,即。一个库,建议您选择以下知名方案之一,并在您的库中始终如一地使用它:
Truth 1/0 - 数字 - 与其他语言最便携,更易于打印
Truth 1/!!0 - 最像标准 Perl 关系运算符,可移植性较差,可打印性较差(除非您希望 false 不可见)
这个答案强调布尔函数或方法,谓词。它不是试图讨论非布尔函数,它们返回实际的东西,如数字、字符串或引用 - 除了下面简要介绍。
@DaveCross 提出了另一个有趣的方案
-
return 1 / return 什么都没有(几乎是1/(),空列表)
我记得 Perl 早期的一个方案 - 在 refs 之前,我认为甚至在 undef 是可以返回的值之前。但是 IIRC 这个方案和 use warnings 存在问题,可能还有?:,所以我犹豫是否完全推荐它,直到有人更好地解释如何避免此类问题。可能使用wantarray。
---++选择1/0或1/0!! (原生 Perl)并保持一致
我建议您选择其中一种布尔方案,并始终如一地使用该方案。
1/0 布尔方案可能最适合其他语言。
1/!!0 方案将使您的代码更接近原生 Perl 运算符。
如果你使用1/!!0方案,不要说“return 0”,说return !!0。
如果你使用1/0方案,不要说return $a < $b,而是说return 0+($a < $b)
如果您调用的代码使用不同的布尔方案(或者可能没有一致的方案),请使用诸如
之类的运算符转换为您在代码中使用的布尔方案
-
!! 规范化标准 Perl 1/0!! 布尔值
-
0+ 或 1* 从标准 Perl 1/0 转换为更便携的 1/0 布尔值!!布尔值
-
?: 和 Perl 的所有其他工具库中的 undef 和字符串可能会或可能不想被视为错误或失败
如果查看返回 ref 或 undef 的函数的返回值
下面的细节太多了。
---++ 可能?:返回 1 或什么都不返回方案(可能是 1/()?)
@DaveCross 提出了一个有趣的建议:
---++ 反推荐:不要混合布尔方案
例如,在同一个函数或库中,不要这样做
return $arg1 < $arg2; # returning a standard Perl 1/!!0 Boolean
在一个地方,然后在其他地方,或者在相同代码的后续演变中,这样做
return 0;
return undef;
return '';
return ();
即选择一种布尔方案,并保持一致。主要是,这涉及到错误值的一致性;在较小程度上是真正的价值。
---+过分凌乱的细节
---++ 在别处讨论 Perl 的许多真理价值
What do Perl functions that return Boolean actually return 和Why does Perl use the empty string to represent the boolean false value? 等帖子讨论了 Perl 布尔函数和运算符实际返回的内容。基本上是特殊值,其行为由 Perl 手册指定。
@cim 链接到 perl 手册:http://perldoc.perl.org/perlsyn.html#Truth-and-Falsehood
真假
数字 0、字符串 '0' 和 "" 、空列表 () 和 undef
在布尔上下文中都是错误的。所有其他值都为真。
对真实值的否定!或不返回一个特殊的假值。
当评估为字符串时,它被视为 "" ,但作为数字,它
被视为 0。大多数返回 true 或 false 的 Perl 运算符的行为
这边。
类似http://perldoc.perl.org/perlop.html#Relational-Operators
关系运算符
返回 true 或 false 的 Perl 运算符通常返回的值
可以安全地用作数字。例如,关系运算符
在本节中,下一节中的相等运算符返回 1
对于定义的空字符串 "" 的 true 和特殊版本,它
算作零,但不受有关不正确数字的警告的影响
转换,就像“0 但真实”一样。
不幸的是,What do Perl functions that return Boolean actually return 的接受答案
讨论内部结构,然后推荐
my $formatted = $result ? '1' : '0';
这又回到了我们开始的地方。
@amon 在对问题 What do Perl functions that return Boolean actually return 的评论中向我们展示了光芒 (!!)
旁注:您可以将任何值转换为相应的布尔值
双重否定。这导致了!!伪运算符。非常有用
返回通用的真值或假值而不是一些魔法
数字。 – 阿蒙 2012 年 11 月 22 日 22:11
这些特殊的布尔值似乎没有任何文字。然而,产生它们的方法有很多:(0<0)、(0<1) 等。(!!1) 和(!!0) 可能是最好的——尤其是因为在某些 C/C++ 编程圈子中它们用于类似目的。另外,!! 可以应用于传入的真值,以将其“标准化”为这个“Perl 标准”布尔值。
---++ 反推荐:不要混合布尔方案
例如,在同一个函数或库中,不要这样做
return $arg1 < $arg2; # returning a standard Perl 1/!!0 Boolean
在一个地方,然后在其他地方,或者在相同代码的后续演变中,这样做
return 0;
return undef;
return '';
return ();
即选择一种布尔方案,并保持一致。主要是,这涉及到错误值的一致性;在较小程度上是真正的价值。
例如避免从
演化代码
return $arg1 < $arg2; # returning a standard Perl 1/!!0 Boolean
到
if( $arg1 < $arg2 ) {
log_or_print('found $arg1 <$arg2');
# other stuff to do if less-than
return 1;
} else {
log_or_print('found not( $arg1 < $arg2)');
# other stuff to do if not-less-than
# which may not be the same thing as greater-than-or-equal
return 0;
}
或
if( $arg1 < $arg2 ) {
...
} else {
...
return undef;
}
从其他地方来到 Perl,您可能会认为它们是等价的,而且大多数情况下是等价的,但如果您在测试中执行诸如打印布尔返回值之类的操作,您会发现差异。
如果您从 Perl-ish 布尔运算符演变代码
return $arg1 < $arg2; # returning a standard Perl 1/!!0 Boolean
进化成
if( $arg1 < $arg2 ) {
log_or_print('found $arg1 <$arg2');
# other stuff to do if less-than
return 1;
} else {
log_or_print('found not( $arg1 < $arg2)');
# other stuff to do if not-less-than
# which may not be the same thing as greater-than-or-equal
return !!0;
}
如果您希望行为尽可能接近相同。注意 false 返回的 !!0,据我所知,没有更简单的方法可以构造 Perl 对 false 的特殊返回值。
相反,如果你想使用 1/0 布尔方案,它们的原始代码应该写成
return 0+($arg1 < $arg2); # returning a standard Perl 1/!!0 Boolean
---++ 从 value / undef 创建谓词
同样,你可能会想使用诸如
之类的功能
sub find_string_in_table {
# returns string value if found, undef if not found
return $lookup_table->{$_[0]};
}
并将其重构为谓词
sub is_string_in_table {
return find_string_in_table(@_);
}
然后可能会演变为进行健全性检查或性能优化。
sub is_string_in_table {
return 0
# don't even bother for long strings
if 1000000 < length($_[0]);
return find_string_in_table(@_);
}
这既不是 1/0 也不是 1/!!0,也不是始终如一的 value/undef。
(注意:我不是说这个预检查是性能优化 --- 但我是说性能优化可能看起来像上面。性能优化是我的专长之一,你希望这样的优化是重构. 当优化的代码表现更好时,它很糟糕,但在某些地方使用它时会中断。因此,我对执行完全一样的代码感兴趣......无论它被替换,就像本机 Perl 关系运算符一样。完全意味着完全。)
如果您使用的是标准 Perl-ish 布尔值,请改为执行以下操作。
sub is_string_in_table {
return !!0
# don't even bother for long strings
if 1000000 < length($_[0]);
return (defined find_string_in_table(@_));
}
或者如果您使用的是 1/0 布尔值
sub is_string_in_table {
return 0
# don't even bother for long strings
if 1000000 < length($_[0]);
return 0+(defined find_string_in_table(@_));
}
如果使用 find_object_ref_in_table 而不是 find_string_in_table,您可能只需要返回 0+!!find_string_in_table(@_),因为您不需要担心像 q() 和 "0" 这样的字符串。
如果您希望您编写的代码中的布尔函数表现得像本机 Perl 运算符,则返回 (!!1) 表示真,返回 (!!0) 表示假。
即0/1,但使用 ! 逻辑否定两次运算符将您的 1 或 0 转换为 Perl 的“本机”布尔值。
例如
sub my_boolean_function {
...
return !!1; # true
...
return !!0; # false
}
**---+ 0/1 --> 1/!!0 转换**
如果你考虑!作为从“元布尔”到“特殊布尔”的转换,
将 1* 或 0+ 视为从特殊布尔值到普通 0/1 布尔值的转换。
例如print "test".(1*($a eq $b))."\n"
例如print "test".(0+($a eq $b))."\n"
?:更笼统,但更冗长。
---++ 非布尔错误返回
这个问题和答案强调布尔函数或方法,谓词。它不是试图讨论非布尔函数,它们返回实际的东西,如数字、字符串或引用 - 除了下面简要介绍。
将返回值扩展为表示特殊情况(例如失败、无效输入等)是“不错的”,并且可以在 IF 语句或其他控制流(例如 and 和 or 运算符)的上下文中对其进行评估,通常用于处理此类错误,例如提供默认值。
我们将对非布尔函数的讨论限制在这个简短列表中:
value/undef 在undef 不是合法返回值时效果最佳,并且当 undef 是合法值时可能会出现问题。想象一个返回哈希字段值的访问器函数,$hash->{field}——该字段可能合法地具有值{ field => undef },因此返回 undef dfoes 无法区分不存在的字段和存在但具有的字段一个 undef 值。
- 任意字符串,可以根据上下文解释为数字或布尔值。
- "0 but true" - 我真的不想进入这个,但是看看What does "0 but true" mean in Perl? 对字符串 "0 but true" 的特殊处理。其他字符串在转换为数字时会发出警告,但“0 但为真”不会。
- “0E0” - 类似地,一些 Perl 代码返回字符串“0E0”,其计算结果为 0 作为数字,但作为布尔值返回 true
GLEW 个人意见:因为我编写的代码经常需要移植到其他语言,所以我不喜欢利用像 0+"0 but true" 这样的 Perl 特定技巧。 "0E0" 至少更便携,如果你想象在 C 之类的其他语言中,函数 convert_string_to_float("0E0") 或 convert_string_to_int("0x0")。我更喜欢"0x0",因为它与 x 看起来很特别,而0x0 是一个整数值,而0E0 在某些语言中被解释为浮点数,因此更容易出错。
---++ 可能?:返回 1 或什么都不返回方案(可能是 1/()?)
@DaveCross 提出了一个有趣的建议:
这很重要,因为真值和假值在标量和列表上下文之间可能存在细微差别。想象一个像这样的子程序:...
@DaveCross 继续说明如果在数组上下文中评估布尔函数,返回空列表以外的任何值如何导致错误性丢失。甚至 @array=(undef) 的评估结果都是 true。
我希望这个方案能够奏效。我想我几年前在 Perl 4 或更早的版本中使用过它,但是当 use warnings 开始成为该做的事情时就放弃了。
就我的记忆而言,我也遇到了条件表达式的问题?:遵守这个约定。
我都尝试过“return;”和“return();”
考虑
% perl -wle 'print "a()=<<".a().">>\n"; sub a {if(@_) {return 1} else {return}}'
Use of uninitialized value in concatenation (.) or string at -e line 1.
a()=<<>>
% perl -wle 'print "a()=<<".a().">>\n"; sub a {if(@_) {return 1} else {return ()}}'
Use of uninitialized value in concatenation (.) or string at -e line 1.
a()=<<>>
% perl -wle 'print "a()=<<".a().">>\n"; sub a { return @_ } '
a()=<<0>>
% perl -wle 'print "a()=<<".a().">>\n"; sub a { return !!@_ } '
a()=<<>>
%
---+底线
使用1/0(可打印和便携)、1/0!!(最类似于 Perl 的本机布尔函数)。
可能return 1 或return 什么都没有,这与1/() 几乎相同。 (但我在使用这种方法时遇到了问题。)
避免在同一函数或库中混合数字 1/0、Perl 的原生条件、undef 和其他方案。
最后,如果你曾经做过
$> perl -wle 'print false && true'
你可能已经收到了
Unquoted string "false" may * with future reserved word at -e line 1.
Unquoted string "true" may * with future reserved word at -e line 1.
Bareword found in conditional at -e line 1.
true
所以似乎有一天 Perl 可能会为布尔值提供一个“官方”方案,其值为 true 和 false。
我想知道它们会如何表现?