---+ 简短回答
以下是 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
布尔值,只要您不关心 false 值是否不可见,即空字符串。
避免在同一函数或库中意外混合数字 1/0、Perl 的本机条件和其他方案。undef
故意混合时,使用转换运算符,例如
!!$bool_0or1
转换为传统的1/!!0
Perl 值
(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 错误,例如在列表上下文中返回布尔标量 false (如 0 或 undef),它会变为 true
(1)/(0)
- 返回一个包含 1 的长度为 1 的列表,或一个空列表。与 类似1/()
,在 true 和 false 都是数组的意义上是一致的。
1/undef
- 另一种可能性,捕获1/()
返回 1 或什么都不会导致的错误
我毫不犹豫地推荐这些。至少,1/()
是不一致的,但是……它们肯定已经被 Perl 程序员使用过,所以你应该准备好处理使用这些方案的代码。即准备调试由这些方案引起的错误。
1/()
return 1;
是我尝试为返回 true的函数和返回 false 的函数做的方案创建缩写名称return;
,即没有操作数值的返回。即返回 1 或无。我相信return nothing等同于return ();
. 此方案可保护您免受程序员在列表上下文而不是标量上下文中评估您的函数引起的错误。但它会使您暴露于诸如{1=>return_nothing_if_false(),2=>return_nothing_if_false()}
(snce 您可能不想要{1=>2}
.
顺便说一句,我认为执行该方案可能更一致(1)/()
。这将允许您始终如一地拥有这种布尔类型的变量,当然是@array
变量。
请注意,这1/undef
不等同于上述任何一项。 当 false=被打印或插值或用于算术时,1/undef
布尔变量会发出警告,但当 true=1 被如此操作时不会发出警告,并且在列表上下文中评估为 true。undef
有人可能会说它具有所有方案中最差的特征。
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 将许多不同的值解释为真或假。
如果您正在创建一系列相关功能,即。一个库,建议您选择以下知名方案之一,并在您的库中始终如一地使用它:
真相1/0
- 数字 - 最便携/来自其他语言,更可打印
真相1/!!0
- 最像标准 Perl 关系运算符,不那么便携,不那么可打印(除非你想让 false 不可见)
这个答案强调布尔函数或方法,谓词。它不是试图讨论非布尔函数,它返回实际的东西,如数字、字符串或引用 - 除了下面简要介绍。
@DaveCross 提出了一个额外的有趣方案
return 1
/return
没有(几乎1/()
,空列表)
我记得 Perl 早期的一个方案 - 在 refs 之前,我认为甚至之前undef
是一个可以返回的值。但是 IIRC 这个方案有问题,你se warnings
也可能有问题?:
,所以我犹豫是否完全推荐它,直到有人更好地解释如何避免这些问题。可能使用wantarray
.
---++ 选择 1/0 或 1/0!!(本机 Perl)并保持一致
我建议您选择其中一种布尔方案,并始终如一地使用该方案。
1/0 布尔方案可能最可移植到其他语言。
1/!!0 方案将使您的代码更接近于本地 Perl 运算符。
如果您正在使用该1/!!0
方案,请不要说“返回 0”,说return !!0
.
如果您正在使用该1/0
方案,请不要说return $a < $b
,而是说return 0+($a < $b)
如果您调用的代码使用不同的布尔方案(或者,可能没有一致的方案),请使用以下运算符转换为您在代码中使用的布尔方案
!!
规范化标准 Perl1/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 的许多真理价值
诸如返回布尔值的 Perl 函数实际返回什么以及Perl 为什么使用空字符串来表示布尔值 false 之类的帖子?讨论 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 但真实”是。
不幸的是,对于返回 Boolean 的 Perl 函数实际返回什么的公认答案
讨论了内部结构,但随后建议
my $formatted = $result ? '1' : '0';
这又回到了我们开始的地方。
@amon 在对返回布尔值的 Perl 函数实际上返回什么问题的评论中向我们展示了光 (!!)
旁注:您可以使用双重否定将任何值转换为相应的布尔值。这导致了!!伪运算符。对于返回通用的真值或假值而不是一些幻数非常有用。– 阿蒙 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_string_in_table 而是 find_object_ref_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} - 该字段可能合法地具有 value { field => undef }
,因此返回 undef dfoes 不能区分不存在的字段和存在但具有 undef 值的字段。
- 任意字符串,可以根据上下文解释为数字或布尔值。
- “0 但真实” - 我真的不想进入这个,但看看Perl 中的“0 但真实”是什么意思?用于字符串“0 but true”的特殊处理。其他字符串在转换为数字时会发出警告,但“0 但为真”不会。
- "0E0" - 类似地,一些 Perl 代码返回字符串 "0E0",它作为数字计算为 0,但作为布尔值返回 true
GLEW 个人意见:由于我编写的代码经常需要移植到其他语言,因此我不喜欢利用 Perl 特有的技巧,例如0+"0 but true"
. "0E0"
如果您想象在 C 等其他语言中是函数convert_string_to_float("0E0")
或convert_string_to_int("0x0")
. 我更喜欢"0x0"
它,因为它与 x 看起来很特殊,并且0x0
是一个整数值,而0E0
在某些语言中被解释为浮点数,因此更有可能给出错误。
---++ 可能?:返回 1 或不返回任何方案(可能是 1/()?)
@DaveCross 提出了一个有趣的建议:
这很重要,因为真值和假值在标量和列表上下文之间可能存在细微差别。想象一个像这样的子程序:...
@DaveCross 继续展示如果在数组上下文中评估布尔函数,返回空列表以外的任何值如何导致错误性丢失。甚至@array=(undef)
评估为真。
我希望这个计划能够奏效。use warnings
我想我几年前在 Perl 4 或更早的版本中使用过它,但是当它开始成为要做的事情时就放弃了。
据我记得,我也遇到了条件表达式的问题?:遵守这个约定。
我已经尝试了两个“返回”;和“返回();”
考虑
% 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/()
. (但我在使用这种方法时遇到了问题。)
避免undef
在同一个函数或库中混合数字 1/0、Perl 的本机条件、和其他方案。
最后,如果你曾经做过
$> perl -wle 'print false && true'
你可能已经收到
Unquoted string "false" may clash with future reserved word at -e line 1.
Unquoted string "true" may clash with future reserved word at -e line 1.
Bareword found in conditional at -e line 1.
true
所以似乎有朝一日 Perl 可能会为布尔值提供一个“官方”方案,其值为 true 和 false。
我想知道那些将如何表现?