为什么在布尔值变量上使用!boolean_variable == false


59

关于此问题的评论:检查方法是否返回false:将结果分配给临时变量,还是将方法调用直接置于条件中?说应该在测试条件时使用!boolean而不是boolean == false。为什么?对我boolean == false来说,英语更加自然,也更加露骨。抱歉,这仅是风格问题,但我想知道是否还有其他原因导致这种偏好!boolean


28
写起来短些。
泽农

39
这就像在做boolean == true:没有意义。内部表达式if语句只是:表达式。如果某些内容已经求值为布尔表达式,为什么还要添加一个检查以强制其求值呢?
Maxpm 2012年

10
@zzzzBov:嗯,不。大多数(C风格)的程序员并不是这样做的。
amara 2012年

9
@zzzzBov:您的评论模棱两可。如果您是!boolean_variable大多数C程序员那样做的话,我同意。
基思·汤普森

29
更重要的是,没人愿意写东西怎么来boolean != true

Answers:


153

当我看到这样的一行时 if (!lateForMeeting()),我将其读为“如果不迟到开会”,这很容易理解,而if (lateForMeeting() == false)我读为“如果我迟到开会的事实是错误的” “

它们的含义相同,但是前者更接近于构造等效的英语句子的方式。


27
+1在Python中,您实际上编写了if not late_for_meeting:)
phunehehe 2012年

42
我认为,如果“如果___为假”听起来比“如果不是____”更自然,那么____的名称就需要改进。
Mike DeSimone'2

12
在Perl中您可以写作unless late_for_meeting
Henrik Ripa '02

4
@HenrikRipa:似乎您可以输入的任何内容都是Perl中的合法代码。它是否满足您的要求是另一个问题;)
Adam Robinson

4
@ A-Cube我将没有像这样的方法。相反,我有一种称为的方法done()。双底片不好。
kba 2012年

97

写作== false== true是多余的。它也可以被带到任意的极端。如果你开始写作

if (condition == false) { ... }

那为什么不

if ((condition == false) == true) { ... }

还是为什么不

if ((someExp == anotherExp) == true) { ... }

这个故事的寓意是,如果condition是布尔表达式,则无需添加== false;这就是运算符!的作用;)


没想到这个!
2012年

51
== false不是多余的,只是比冗长!。OTOH,== true是多余的。
dan04 '02

4
@ dan04你是对的。但是,就我的意思而言,这仍然不是一个好主意。考虑(exp1 != exp2)((exp1 == exp2) == false)。诚然,这些都是人为设计的方案,但是您仍然几乎永远都不要写对或错的显式比较。正如您应该使用运算符一样!=,您也应该使用!
安德烈斯·F

26
@ dan04:当该语言已提供时,这是多余的!
DeadMG

5
@ dan04:任何时候写bool_expression == bool_literal== ...都是多余的。无论测试的是真还是假都是无关紧要的。这只是后续块/替代块顺序的变化。安德列斯的例子很好地说明了这一点。大多数现代的编译器都会优化冗余,但是它仍然是冗余的。
冒犯君主

70

在C语言和某些类似语言中,比较布尔表达式是否等于falsetrue具有危险习惯。

在C语言中,任何标量表达式(数字或指针)都可以在布尔上下文中使用,例如,作为if语句的条件。C规则if (cond)等效于if (cond != 0)-即零为false,任何非零值为true。如果cond是指针类型,则将其0视为空指针常量;否则为false。if (ptr)意味着if (ptr != NULL)

这意味着

if (cond)

if (cond == true)

没什么意思。如果cond非零,则第一个为true;否则为false 。第二个只有在等于时才是正确的true,在C中(如果有的话#include <stdbool.h>)就是1

例如,如果参数为数字,则isdigit()in中声明的函数<ctype.h>将返回一个int值,0否则为非零。它可以返回42以表明条件为真。比较42 == true将失败。

碰巧这0是唯一被认为是错误的值,因此比较是否相等false将起作用。if (!cond)if (cond == false)做同样的事情。但是,如果要利用这一点,则必须记住,与进行比较false是可以的,而与进行比较是不可行的true。更糟糕的是,相比true将工作的大部分时间(例如,平等,关系运算符总是产生两种01)。这意味着使用此工具引入的任何错误仍然可能很难找到。(不用担心,一旦您将代码演示给重要的客户,它们就会出现。)

C ++的规则略有不同。例如,其bool类型与语言紧密集成在一起,并if (cond)转换cond为type bool。但是效果(大部分)是相同的。

其他一些语言具有所谓的行为更佳的布尔值,因此cond == truecond == false(或任何语法碰巧)都是安全的。即使这样,我见过的每种语言都有一个notor !运算符;它在那里,所以您不妨使用它。使用cond == false而不是!condnot cond不,在我看来,提高可读性。(确实,!角色一目了然很难看到;!为避免这种情况,我有时会在其后添加一个空格。)

通常,您可以通过稍微重新排列代码来避免此问题提高清晰度。例如,而不是:

if (!cond) {
    do_this();
}
else {
    do_that();
}

您可能会写:

if (cond) {
     do_that();
}
else {
    do_this();
}

这并不总是更好,但是在适当的地方寻找机会也没有什么坏处。

摘要:在C和C ++,平等比较,true并且false是危险的,过于冗长,差的风格。在许多其他语言中,这样的比较可能并不危险,但它们仍然过于冗长且风格欠佳。


+1是唯一的答案,其中包含实际有用的技术说明。
Mike Nakis 2012年

我仍然以这种方式思考,无论使用哪种编程语言,我始终认为这== true是不安全的。这样感觉更好。
Dervall

1
@Dervall:假设事实并非如此,那也没有好处。在某些语言中,存在一些极端的情况,布尔值的相等比较不仅安全而且实际上是适当的,例如在Haskell中,该语言具有强大的无隐式转换类型系统,并且具有双向类型推断功能,有人可能会写(==True) . f清楚这一点我们想要-> Bool返回多态函数的实例化f。这比清楚not . not . f,少了尴尬(f :: a -> Bool)
leftaboutabout

另外,做诸如pred(x)==pred(y)布尔返回函数之类的事情当然是合适的predpred(x)? pred(y) : !pred(y)您将同意的另一种选择几乎是不可接受的。
大约

1
@leftaroundabout:如果您知道这一点pred(x)pred(y)使用相同的值表示真相,那很好,在某些语言中这是一个安全的假设,而在其他语言中则不是。例如,在C中,您可以编写!!pred(x) == !!pred(y)
基思·汤普森

13

如果condition == false确实对您来说“英语更加自然”,那么我必须假定您不是母语人士。否则我无法解释这一点,因为没人会这样说:

如果阳光明媚,那我就呆在家里。

比较一下

如果没有阳光,我待在家里。

就是说,我同意!在代码中很容易忽略单个细长的字符。因此,not当语言支持时,我更喜欢使用关键字。例如C ++ 确实允许这样做,尽管许多程序员对此并不了解。

对于需要的语言!,我在运算符和操作数之间放置一个空格。这使否定变得更加难以忽略:

if (! condition) { … }

请注意,每个程序员都应自动将其翻译为“无条件”,而无需三思。在阅读代码习惯时获得这种流利程度是成为一名优秀程序员的第一步。


13

两者在功能上是相同的,因此使用哪一个取决于口味。

使用的主要原因== false是,我发现!在查看代码时太容易忽略了。

被这个问题严重咬伤后,我养成了在测试错误时非常清楚的习惯。


如果操作员not在Pascal中被命名为,我认为这不会成为问题。


5
出于这个原因,我为某些医疗设备软件开发的C ++项目具有一个强制执行的编码标准,== false而不是!出于同样的原因(使其脱颖而出)。但是,不需要使用== true,因此任何非零值仍然可以正常工作。
tcrosley 2012年

12
我总是觉得这种说法令人信服-C / C ++ / C#/ Java / etc中的其他地方,如果看不到单个字符,对代码的解释也会产生类似的重大影响。选出“!” 因为唯一的坏事对我来说毫无意义。
Bevan 2012年

5
@bevan显然您尚未被咬。

1
尽管我同意忽略!可能是此类问题中最麻烦的一个,但IMO不应养成写作的习惯,==false而应养成编写更好的单元测试的习惯。
leftaboutabout

8
@ThorbjørnRavnAndersen恰恰相反-多年来,我经常被咬伤,以至于我学会了自己阅读每个角色。我不是我每天必须阅读的所有(或什至大多数)代码的作者,因此,我们在此处讨论的任何个人约定都没有什么价值:我需要正确理解我阅读的所有代码,而不是只是我写的东西。
Bevan 2012年


6

因为有时您可能会写boolean = false(带有明显的错误)并且false == boolean看起来并不自然(无论练习有多好)


很久以前,当我第一次开始编程时,我的一位导师建议我养成if( INVALID_HANDLE_VALUE == hFile )避免这种事情的习惯。这样,如果您滑倒并使用一个等号而不是两个,则会出现编译器错误。显然,这仅在左表达式为常数时有效,但是它为我节省了比我数不胜数的头痛。
德鲁·查平

如果您使用静态分析工具,则可以为您节省数百倍的头痛,并且可以恢复自然hFile==INVALID_HANDLE_VALUE 书写。
Gqqnbig

4

if (!boolean_variable)转换为if the condition is not true

if (boolean == false)转换为if the condition not false is true。因为那是逆逻辑,所以很难理解。


3
!true表示不正确。!boolean 取决于布尔值本身是逻辑取反,它表示不是false 不是true。
S.Robins'2

1
@ S.Robins我发现布尔值的愚蠢名称是布尔变量。例如类似的东西isVisible将是一个更好的例子。则if (!isVisible)意味着如果不可见-则比起来更容易理解if (isVisible==false),这是一种逆逻辑。希望现在更清楚。还是我误解了您的评论?
2012年

2

在(很多)较旧的编译器中,我相信它们会将(布尔==假)分解为2个寄存器分配和一个机器语言比较代码。第一个示例将分为一个赋值和一个NOT运算符。就性能而言,与按位取反(1个时钟)相比,比较操作将花费多个时钟周期,具体取决于要比较的寄存器的大小,并且执行起来会较慢。

话虽这么说,我相信较新的编译器可以解决这个问题,因此可以选择两者之一。


生成机器代码是编译器的工作,而不是高级语言程序员的工作……
CVn 2012年

由于历史原因,这很可能是一种方法变得比另一种方法更受欢迎的原因之一。
Legolas 2012年

1

在工作中,我经常处理可以为null的布尔值,因此我经常将这种情况编码为

if (value != null && value == true){
    //do something
}

因为我个人觉得对称使阅读更容易。特别是如果还有其他布尔值也在测试中。

我真的不在乎一种方式。


4
如果value == true这样,则没有理由检查它是否不为null。如果value == null它从不应该首先触发if语句,那么if (value)就足够了。
zzzzBov 2012年

1
布尔值是对象(在Java中),因此可以为null,因此只需说if (value)会引发异常。如果不赞成的人给出理由,我将不胜感激。
WuHoUnited '02

3
我只是碰巧看到了这一点,没有拒绝投票。布尔空值不是一个好习惯。为什么?因为布尔值通常表示打开某种东西的状态。在大多数情况下,您可能希望在一开始就将其声明为false,然后随行为对其进行更改。看到布尔值未初始化是非常罕见的。
茄子

我必须在这里同意Aubergine的观点,我本人已经陷入了一个坏习惯(尤其是在Java中),即不对布尔值进行初始化,然后最终检查是否为null。我认为这更多是语言的一个缺陷,但是这会给用户带来该缺陷。在我看来,声明新的bool变量时,应默认为false而不进行初始化。

2
@WuHoUnited,即使该值为空,value == true也足够。
zzzzBov 2012年

1

当测试真实条件时,只做一次就很有意义if (condition),尤其是当您应用以'is'开头的布尔变量命名约定时:if (isOpen)完全清楚,使用!= false将是多余的。

对于C / C ++ / Java / etc。程序员的意思是“!” 操作符被完全吸收,以至于我们在看到它时会自动想到“ not”。所以拥有对我来说if (!isOpen)很清楚if (_NOT_ isOpen)。但是您还不够熟悉,在C / C ++中,您可以使用创建宏#define _NOT_ !。但是请相信我,几年后这完全没有必要。

除此之外,始终最好测试布尔值而不将它们与文字进行比较。例如,进行测试if (x == true)是很危险的,因为如果布尔值不为零,则布尔值被视为true,而文字true仅有一个特定值,因此x可能为“ true”(即非零),并且比较结果仍为false(因为它是包含2,而字面的true表示为1。)当然,这不适用于带有false的比较,但是如果在测试true时不使用它,为什么在测试false时使用它?


不必制作您建议的C ++宏,因为C ++已经知道“不是”。相关:stackoverflow.com/questions/2393673/c-and-or-not-xor-keywords
Frozenkoi 2012年

没错,但这只是C ++ 0X标准的关键字。在此之前,它只是另一个宏。
法比奥·塞科内洛

0

大小事项 ;)

在混合表达式中,更容易阅读:

boolean1 = false
boolean2 = true

p ! boolean1 and ! boolean2
p boolean1 == false and boolean2 == false

特别是在红宝石方面,有一个很大的区别:

boolean = nil
p ! boolean         #-> true
p boolean == false  #-> false

nil不是假的,但也不是真的。


0

根据我的经验以及您所链接的问题的答案。

有些人更喜欢使用if(condition),因为它写的时间较短。对我来说,这实际上是有道理的,例如(!isValidated())我读为“未验证”。但对我而言,这全都是基于个人喜好,并且取决于isValidated()方法的逻辑结构,无论它返回true还是false


0

如果您正确命名了变量,则!boolean更为自然。not boolean对于任何一个足以使程序员能够精读代码的人来说,它的读物都是如此。


0

对于某些人来说,越早表达意思就越好。

对于那些拥有“ if!...”的人来说,它们比“ if ...”要快得多,因此必须通读整个条件(实际上可能很长,例如(thisThing = thatThing或某物=另一件事)或(只是找到末尾的== false。

有!(我实际上更喜欢在语言允许的情况下使用not)在这种情况下,就可以提前获得英语的“ not”。

这个问题也导致考虑使用until支持它的语言,例如做“常见的事情”直到事情完成。正如其他人所说,自然语言表达是目标。我喜欢上面的“阳光明媚”示例。


0

另一个原因是,如果您在使用多种语言的代码库中工作,那么如果有一种惯用的方式来完成所有语言中的安全操作,那么在所有地方都采用这种方式是一个非常好的主意,以便您养成良好的习惯并且不太可能绊倒。

我想不出任何地方if (!variable)(或等价物如if not variable根据您的语言)是不是安全的,而如if self.is_ready() == False: ...没有安全的蟒蛇,如果self.is_ready()回报率None,现在还是将来,这将是一个完全合理的事情为它做表示还没有准备好,因为None和一样虚假False

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.