开发人员坚持认为,语句不应具有否定条件,而应始终具有else块


169

我有一个相识的人,一个比我经验丰富的开发人员。我们在谈论编程实践,而他对“ if”语句的处理方式让我感到惊讶。他坚持一些关于if陈述的做法,我觉得这很奇怪。

首先,在if语句后应加上else语句,无论是否要放入其中。导致代码如下所示:

if(condition) 
{
    doStuff();
    return whatever;
}
else
{
}

其次,最好测试真值而不是假值。这意味着最好测试“ doorClosed”变量而不是“!doorOpened”变量

他的观点是,这使代码的工作更加清晰

这让我很困惑,因为如果他想在不满足条件的情况下执行某些操作,那么这两个规则的组合会使他编写此类代码。

if(condition)
{
}
else
{
    doStuff();
    return whatever;
}

我对此的感觉是,它确实很丑陋和/或质量改进(如果有)可忽略不计。但是作为一个大三学生,我很容易怀疑自己的直觉。

所以我的问题是:这是好/坏/“无关紧要”的做法吗?这是惯例吗?



57
您的同事是否可能来自可能危及生命和肢体的背景?我相信我已经在系统中看到过这样的事情,其中​​对代码进行了大量的测试和自动分析,而在错误的地方可能会真正使某人丧命。
jpmc26 2015年

11
您的公司代码风格指南怎么说?
托尔比约恩Ravn的安德森

4
对您的“第二个”问题的部分回答。如果其中一个动作块很长而另一个动作块很短,请测试将短块放在首位的条件,这样在读取代码时就不会错过它。该条件可以是否定条件,也可以重命名以使其成为真实测试。
伊桑·博克

9
Resharper会告诉您的朋友,“您的代码是多余且无用的,您要我删除/重构它的代码吗?”
BgrWorker

Answers:


184

显式else

第一条规则只会污染代码,使其既不易读,也不易出错。我想,您的同事的目标是明确的,表明开发人员完全意识到条件可能会评估为false尽管明确是一件好事,但这样的明确性不应以额外的三行代码为代价

我什至没有提到以下事实:一个if语句不一定要跟一个else或不跟:它也可以跟一个或多个elif

return声明的存在使情况更糟。即使您实际上有代码要在该else块内执行,这样做也更容易理解:

if (something)
{
    doStuff();
    return whatever;
}

doOtherThings();
return somethingElse;

这使代码少占用两行,并且使代码else块缩进。保护条款就是关于这一点的。

但是请注意,您同事的技术可以部分解决非常讨厌的无条件堆叠条件块模式:

if (something)
{
}
if (other)
{
}
else
{
}

在先前的代码中,在第一个代码if块之后缺少合理的换行符,这很容易误解代码。但是,尽管您的同事的规则会使误读代码更加困难,但更简单的解决方案是仅添加换行符。

测试true,而不是false

第二条规则可能是有道理的,但不是目前的形式。

毫无疑问,对关闭的门进行测试比对未打开的门进行测试更为直观。否定,尤其是嵌套否定,通常很难理解:

if (!this.IsMaster || (!this.Ready && !this.CanWrite))

为了解决这个问题,而不是添加空块,而是在需要时创建其他属性或局部变量

上面的条件可以很容易地变得可读:

if (this.IsSlave || (this.Synchronizing && this.ReadOnly))

169
空块在我看来总是像个错误。它会立即引起我的注意,我会问:“为什么在这里?”
尼尔森

50
@Neil否定条件不一定需要任何额外的CPU时间。Ç编译成x86的可能只是交换跳转指令来自JZ于(跳转,如果零)if (foo)JNZ(跳转如果不是零)if (!foo)
8bittree

71
使用清晰的名称创建其他属性 ”:除非您对域进行更深入的分析,否则可能会更改全局范围(原始类)以解决本地问题(应用特定业务规则)。这里可以做的一件事是创建具有所需状态的本地布尔值,例如“ var isSlave =!this.IsMaster”,然后将if应用于本地布尔值,而不是创建其他多个属性。因此,在创建新属性之前,请带着一点建议,花一些时间来分析域。
马查多

82
这不是关于“三行代码”,而是关于为适当的读者(至少具有基本的编程知识的人)编写内容。一个if已经明确的事实,条件可能是假的,不然你不会是测试它。空块使事情变得不那么清楚,而不是更多,因为没有读者愿意期待它,现在他们必须停下来想一想它是如何到达那里的。
hobbs

15
@Mark即使有评论,也不太清楚if (!commonCase) { handle the uncommon case },
Paul

62

关于第一个规则,这是无用键入的示例。不仅要花更长的时间,而且还会给阅读代码的人带来极大的困惑。如果不需要代码,请不要编写。else随着代码从if块返回,这甚至会扩展为在您的情况下没有填充:

if(condition) 
{
    doStuff();
    return whatever;
}

doSomethingElse(); // no else needed
return somethingelse;

关于第二点,最好避免包含负数的布尔名称:

bool doorNotOpen = false; // a double negative is hard to reason
bool doorClosed = false; // this is much clearer

但是,正如您指出的那样,将其扩展为不再测试否定词会导致更多无用的输入。以下内容比空if块要清楚得多:

if(!condition)
{
    doStuff();
    return whatever;
}

120
所以...您可以说双重否定是不可以吗?;)
Patsuan

6
@Patsuan,非常聪明。我喜欢。:)
David Arno

4
我觉得没有多少人会同意应如何处理与收益有关的if-else,甚至有人甚至会说不应在每种情况下都以同样的方式处理它。我本人并没有强烈的偏爱,但我绝对可以看到许多其他方法背后的争论。
Dukeling

6
显然,这if (!doorNotOpen)很糟糕。因此,名称应尽可能正面。if (! doorClosed)很好。
David Schwartz

1
关于您的门示例,两个示例名称不一定相等。在物理世界doorNotOpendoorClosed,开放与封闭之间存在一种过渡状态。我一直在工业应用中看到布尔状态是由物理传感器确定的。如果您在门的打开侧只有一个传感器,则只能说门是打开的还是未打开。同样,如果传感器在关闭侧,则只能说关闭或不关闭。传感器本身也确定如何确认逻辑状态。
Peter M

45

1.支持空else语句的论点。

我经常使用(并主张)类似于第一个构造的东西,一个空虚的东西。它向代码的读者(包括人工分析工具和自动分析工具)发出信号,表明程序员已经对这种情况进行了一些思考。本else应存在的遗漏声明造成人员伤亡,车辆坠毁,并造成数百万美元的损失。例如,MISRA-C至少要求发表一条评论,说遗漏的决赛是有意为之if (condition_1) {do_this;} else if (condition_2) {do_that;} ... else if (condition_n) {do_something_else;}。其他高可靠性标准则更进一步:除少数例外,禁止遗漏else语句。

一个例外是简单的注释,类似/* Else not required */。这表示与三行其他内容相同的意图。不需要其他空值的另一个例外是,对于代码阅读者和自动分析工具来说,显然都是多余的是多余的。例如,if (condition) { do_stuff; return; }类似地,如果用throw somethinggoto some_label1代替,则不需要为空return

2.喜欢的争论if (condition)if (!condition)

这是人为因素。复杂的布尔逻辑使许多人不寒而栗。即使是经验丰富的程序员也必须考虑if (!(complex || (boolean && condition))) do_that; else do_this;。至少将其重写为if (complex || (boolean && condition)) do_this; else do_that;

3.这并不意味着人们应该喜欢空的then陈述。

第二部分说“更喜欢”而不是“你应该”。这是一个准则,而不是一条规则。该准则偏向积极if条件的原因是代码应清晰明了。空的then子句(例如if (condition) ; else do_something;)违反了这一点。它是混乱的编程,甚至使最老练的程序员也可以备份并if以否定形式重新读取条件。因此,首先将其以否定形式编写,并省略else语句(或在授权的情况下保留空白的else或对此进行评论)。



1我写了那么结尾条款returnthrowgoto不需要其他空。显然,不需要else子句。但是呢goto?顺便说一句,安全性至关重要的编程规则有时不允许提早返回,并且几乎总是禁止引发异常。但是goto,它们确实允许使用受限形式(例如goto cleanup1;)。goto在某些地方,这种限制使用是首选做法。例如,Linux内核充斥着这样的goto语句。


6
!也很容易被忽视。太简洁了。
托尔比约恩Ravn的安德森

4
不,如果没有其他内容,则不能更清楚表明程序员已对此进行了思考。这就引起了更多的混乱:“是否计划了某些语句,而他们忘记了,或者为什么有空子句?” 评论要清晰得多。
西蒙(Simon)

9
@Simon:一种典型的形式是else { /* Intentionally empty */ }或类似的形式。空的else满足了静态分析器的盲目查找规则冲突的情况。该评论告知读者,其他空白是故意的。再说一次,经验丰富的程序员通常会忽略不必要的注释,但不会忽略其他注释。高可靠性编程本身就是一个领域。这些构造对局外人来说看起来很奇怪。之所以使用这些构造,是因为我们从硬敲门课程中吸取了教训,这些敲门声在生死攸关或$$$$$$$$$$出现时非常困难。
大卫·哈门

2
我不明白空的else子句不是空的情况下,那么then子句是一件坏事(假设我们选择了这种样式)。我可以看到if (target == source) then /* we need to do nothing */ else updateTarget(source)
Bergi

2
@ThorbjørnRavnAndersennope not是C ++中的关键字,其他按位和逻辑运算符也是如此。请参阅其他运算符表示形式
Ruslan

31

在极少数情况下,我使用一个空的else-branch(有时是一个空的if-branch):很明显,if和else部分都应以某种方式处理,但由于某些重要原因,可以通过以下方式处理该情况:什么也不做。因此,任何人使用所需的else操作读取代码后,都会立即怀疑缺少某些内容并浪费时间。

if (condition) {
    // No action needed because ...
} else {
    do_else_action()
}

if (condition) {
    do_if_action()
} else {
    // No action needed because ...
}

但不是:

if (condition) {
    do_if_action()
} else {
    // I was told that an if always should have an else ...
}

5
这个。我发现该语句if test succeeds -> no action needed -> else -> action needed在语义上与该语句非常不同if it applies that the opposite of a test outcome is true then an action is needed。我想起了马丁·福勒(Martin Fowler)的话:“任何人都可以编写计算机可以理解的代码;优秀的程序员可以编写人类可以理解的代码”。
Tasos Papastylianou

2
@TasosPapastylianou那是作弊。“如果测试成功->无需采取任何措施”的反义词是“如果测试不成功->需采取行动”。您用大约10个单词填充了它。
杰里·B

@JerryB取决于“测试”。有时,否定(从语言上)很简单,但有时却不是,并且会导致混乱。在这些情况下,谈论“否定/结果为真”相对于“结果不为真”更为明确。但是,要点是,引入“空”步骤或反转变量名的含义会更加清楚。这在“ de morgan”情况下是典型的:例如,if ((missing || corrupt) && !backup) -> skip -> else do stuffif ((!missing && !corrupt) || backup) -> do stuff
Tasos Papastylianou

1
@TasosPapastylianou您可以写得if(!((missing || corrupt) && !backup)) -> do stuff更好if((aviable && valid) || backup) -> do stuff。(但在一个真实的示例中,您必须在使用备份之前检查备份是否有效)
12431234123412341234123

2
@TasosPapastylianou我所说的话中有什么双重否定词?当然,如果您使用不损坏的变量名,那么您会很清楚。虽然当你来到混合布尔运算符这样的,它可能是更好的具有临时变量的使用iffile_ok = !missing && !corrupt; if(file_ok || backup) do_stuff();我个人觉得使它更加清晰。
Baldrickk

23

在其他条件相同的情况下,请选择简洁。

您不用写什么,没有人需要阅读和理解。

尽管明确是有用的,但只有在没有过多冗长的情况下就可以清楚地表明您编写的内容确实是您想要编写的内容时,情况才如此。


因此,避免空分支,它们不仅是无用的,而且是罕见的,从而导致混乱。

另外,如果您直接退出if分支,请避免编写else分支。

显式性的一种有用应用是在每次遇到切换情况时都添加// FALLTHRU注释,并在需要空语句的地方使用注释或空块for(a;b;c) /**/;


7
// FALLTHRUgh,不要用SCREAMING CAPS或txtspk缩写形式。否则,我同意并自己遵循这种做法。
科迪·格雷

7
@CodyGray-在这里喊是个好主意。大多数switch语句均以结尾break。未能做到这break一点导致了一些引人注目的软件故障。对代码的读者大声疾呼是故意插入的注释是一件好事。静态分析工具可以寻找这种特定的模式,而不会抱怨失败,这使它变得更好。
David Hammen

1
@Wossname:我刚刚检查了vim,但无法识别的任何变化FALLTHRU。我认为,有很好的理由:TODOFIXME评论是因为你希望能够向你需要成为的grepable评论git grep你有已知的缺陷在你的代码,它们位于何处。失败不是缺陷,因此没有理由对此进行重复。
cmaster

4
@DavidHammen不,喊不是一个好主意:如果您有// fallthrough来代替预期的中断,那对于任何开发人员来说都应该立即理解。同样,// fallthrough并没有说明缺陷,它只是表示已经考虑了情况,并且表明已中断。看起来似乎不见了,确实打算不在那里。这纯粹是提供信息的目的,无可厚非。
cmaster

1
@cmaster-喊喊不是一个好主意,这是您的意见。其他人的意见不同。而且,仅因为无法识别vim 配置FALLTHRU并不意味着其他人还没有配置vim来这样做。
David Hammen

6

据我所知,对于IF声明的正面或负面条件,没有硬性规定。我个人更喜欢在适用的情况下为积极的案例而不是消极的案例编码。如果可以引导我创建一个空的IF块,然后执行一个充满逻辑的ELSE,我当然不会这样做。如果出现这种情况,则大概需要3秒钟将其重构回测试阳性案例。

但是,我真正不喜欢您的示例的是空白的ELSE占用了完全不必要的垂直空间。根本没有任何理由这样做。它不会在逻辑上添加任何内容,也无法帮助记录代码在做什么,也根本不会增加可读性。实际上,我认为增加的垂直空间可能会降低可读性。


2
不必要的垂直空间是必须始终使用花括号,不允许丢失其他内容以及使用Allman样式进行缩进的强制要求的结果。
David Hammen

好吧,我认为始终使用花括号是一件好事,因为它使开发人员的意图明确化-在阅读其代码时没有猜测的余地。这听起来可能很愚蠢,但是请相信我,尤其是在指导初级开发人员时,确实会发生与缺少括号有关的错误。我个人从来都不喜欢Allman风格的缩进,正是因为您提到的原因:不必要的垂直空间。但这只是我的看法和个人风格。这是我最初学习的内容,因此阅读起来总是感觉更舒服。
Langecrew

个人风格:无论我使用哪种花括号样式(Allman,1TB等),我都始终使用花括号。
David Hammen

复杂的条件或您认为可能难以理解的条件几乎总是可以通过重构为它们自己的方法/函数来解决。这样的事情if(hasWriteAccess(user,file))在下面可能很复杂,但是一眼就能知道结果应该是什么。即使只是几个条件,例如if(user.hasPermission() && !file.isLocked()),使用适当名称的方法调用也可以理解这一点,因此否定也不再是问题。
克里斯·施耐德

同意 再说一次,我是重构的
忠实拥护者

5

显式else

我不同意这一点,因为它涵盖了所有if语句,但是有时else出于习惯而增加障碍是一件好事。

一种if说法,在我看来,实际上包括两个不同的功能。

如果我们应该做某事,请在这里做。

像这样的东西显然是没有需要的else部分。

    if (customer.hasCataracts()) {
        appointmentSuggestions.add(new CataractAppointment(customer));
    }
    if (customer.isDiabetic()) {
        customer.assignNurse(DiabeticNurses.pickBestFor(customer));
    }

甚至在某些情况下坚持添加else可能造成误导的内容。

    if (k > n) {
        return BigInteger.ZERO;
    }
    if (k <= 0 || k == n) {
        return BigInteger.ONE;
    }

一样的

    if (k > n) {
        return BigInteger.ZERO;
    } else {
        if (k <= 0 || k == n) {
            return BigInteger.ONE;
        }
    }

即使在功能上相同。if用空写第一个else结果可能会导致第二个结果不必要的丑陋。

如果我们要检查特定状态,通常最好添加一个空白else,以提醒您解决这种情况

        // Count wins/losses.
        if (doors[firstChoice] == Prize.Car) {
            // We would have won without switching!
            winWhenNotSwitched += 1;
        } else {
            // We win if we switched to the car!
            if (doors[secondChoice] == Prize.Car) {
                // We picked right!
                winWhenSwitched += 1;
            } else {
                // Bad choice.
                lost += 1;
            }
        }

请记住,这些规则仅在编写新代码时适用。恕我直言,空else子句应在签入之前删除。


测试true,而不是false

同样,这在总体上是一个很好的建议,但是在许多情况下,这会使代码不必要地变得复杂且可读性较低。

即使代码像

    if(!customer.canBuyAlcohol()) {
        // ...
    }

令读者感到震惊,但却使

    if(customer.canBuyAlcohol()) {
        // Do nothing.
    } else {
        // ...
    }

至少同样糟糕,甚至更糟。

我很多年前用BCPL编码,用这种语言有一个IF子句一个UNLESS子句,因此您可以更容易地将代码编写为:

    unless(customer.canBuyAlcohol()) {
        // ...
    }

明显更好,但仍不完美。


我的个人流程

通常,当我编写代码时,我经常会elseif语句中添加一个空块,以提醒我尚未涵盖这种可能性。这可以帮助我避免DFS陷入陷阱,并确保当我查看代码时,我注意到还有很多事情要做。但是,我通常会添加一条TODO注释来跟踪。

  if (returnVal == JFileChooser.APPROVE_OPTION) {
    handleFileChosen();
  } else {
    // TODO: Handle case where they pressed Cancel.
  }

我确实发现,通常我else很少在我的代码中使用它,因为它通常可以指示代码气味。


在实现thng​​时,您对“空”块的处理就像是标准存根代码...
Deduplicator

unless块是一个很好的建议,并且几乎不限于BCPL。
tchrist

@TobySpeight糟糕。我...原本写的东西确实使我失去了注意return。(实际上,使用k=-1n=-2,会获得第一个收益,但这在很大程度上是没有意义的。)
David Richerby

现代Perl具有ifunless。而且,它还可以在声明后允许它们执行操作,因此您可以说print "Hello world!" if $born;或,print "Hello world!" unless $dead;而两者都将按照您认为的那样做。
CVn

1

对于第一点,我使用了一种强制以这种方式使用IF语句的语言(在Opal中,是将GUI前端放置在大型机系统上的大型机屏幕抓取器后面的语言),并且IF仅用一行和ELSE。这不是一个愉快的经历!

我希望任何编译器都能优化此类额外的ELSE子句。但是对于实时代码,它并没有添加任何内容(在开发中,它可能是进一步代码的有用标记)。

我确实在使用CASE / WHEN类型处理时使用了类似这些额外条款的东西。我总是添加一个默认子句,即使它为空。这是语言的长期习惯,如果不使用这样的子句,它们将出错,并迫使人们思考是否真的应该放弃。

早在大型机(例如PL / 1和COBOL)的实践中,人们就接受否定性检查效率较低的观点。这可以解释第二点,尽管这些天来,效率上的节省更为重要,而微观优化却被忽略了。

负逻辑的可读性确实较低,尽管在这样一个简单的IF语句中不是那么容易理解。


2
我知道了,所以这在某些时候是很普遍的做法。
Patsuan

@Patsuan-是的,在一定程度上。尽管那是大型机汇编程序成为性能关键代码的一种严重替代方法。
Kickstart

1
“很早以前……人们接受否定性检查的效率较低。” 那么,他们除非编译器优化if !A then B; else Cif A then C; else B。计算条件的否定是一条额外的CPU指令。(尽管您说过,这不太可能效率明显降低。)
David Richerby

@DavidRicherby如果我们一般来说,某些语言会使这种优化非常困难。以带有重载!==运算符的C ++ 为例。这并不是说任何人都应该真正做到这一点,你要知道...
一个CVN

1

我会在大多数答案的立场上赞同,说空else块实际上总是有害地浪费电子墨水。除非您有充分的理由这样做,否则不要添加它们,在这种情况下,空块根本不应该为空,它应包含注释以说明为什么存在该块。

但是,关于避免负数的问题值得更多关注:通常,每当需要使用布尔值时,需要设置一些代码块才能对其进行设置,而需要使用其他一些块而无需对其进行设置。这样,如果您强制执行非负数规则,则将强制执行具有if() {} else {...}语句(带有空if块!),或者为每个包含其否定值的布尔值创建第二个布尔值。这两种选择都是不好的,因为它们会使读者感到困惑。

一个有用的策略是:切勿在布尔名称中使用否定形式,而将否定表示为单个!。像这样的陈述if(!doorLocked)非常清楚,像if(!doorUnlocked)打结大脑的陈述。后来式表达的是你需要不惜一切代价避免,而不是单一存在的东西!if()状态。


0

我会说这绝对是不好的做法。添加else语句将在您的代码中添加一堆毫无意义的行,这些行毫无用处,并且使其更加难以阅读。


1
我听说您从未为过根据每个时期产生
的SLOC

0

关于处理具有空if块的第二种情况,还没有提到另一种模式。一种解决方法是返回if块。像这样:

void foo()
{
    if (condition) return;

    doStuff();
    ...
}

这是检查错误情况的常见模式。肯定的情况仍在使用,并且它的内部不再是空的,使未来的程序员不得不怀疑是否有空操作是故意的。由于您可能需要制作新功能(因此将大型功能分解为较小的单个功能),因此它也可以提高可读性。


0

在考虑“总是有else子句”参数时,有一点我在其他任何答案中都没有看到:在函数式编程风格中这是有意义的。有点。

在函数式编程风格中,您处理表达式而不是语句。因此,每个代码块都有一个返回值-包括一个if-then-else表达式。但是,这将排除空白else块。让我举一个例子:

var even = if (n % 2 == 0) {
  return "even";
} else {
  return "odd";
}

现在,在具有C风格或C风格启发性语法的语言(例如Java,C#和JavaScript等)中,这看起来很奇怪。但是,这样编写时看起来更加熟悉:

var even = (n % 2 == 0) ? "even" : "odd";

else此将分支保留为空会导致值未定义-在大多数情况下,并不是我们在编程功能时想要的有效情况。完全省略它也是一样。但是,当您进行迭代编程时,我几乎没有理由总是设置一个else块。


0

...在if语句后应加上else语句,无论是否有内容。

我不同意if (a) { } else { b(); }应改写为if (!a) { b(); },也if (a) { b(); } else { }应改写为if (a) { b(); }

但是,值得指出的是,我很少有空的分支。这是因为通常我登录时会进入原本为空的分支。这样,我可以完全从日志消息中开发出来。我很少使用调试器。在生产环境中,您没有调试器。能够使用与开发相同的工具对生产问题进行故障排除很高兴。

其次,最好测试真实值,而不是错误。这意味着最好测试“ doorClosed”变量而不是“!doorOpened”变量

对此我五味杂陈。具有一个缺点doorClosed,并doorOpened为它有可能增加一倍,你需要知道的字/项的数量。另一个缺点是随着时间的意义doorClosed,并doorOpened可能会改变(其他开发商进来以后你),你可能最终得到两个属性不再彼此精确的否定。除了避免否定之外,我更重视使代码的语言(类名,变量名等)适应业务用户的词汇和给出的要求。我不想编造一个全新的名词来避免!如果该术语仅对业务用户不了解的开发人员有意义。我希望开发人员说的语言与用户和编写需求的人相同。现在,如果新术语简化了模型,那么这很重要,但是应该在需求最终确定之前而不是之后进行处理。开发人员应在开始编码之前处理此问题。

我容易怀疑自己的直觉。

继续质疑自己是件好事。

这是好/坏/“无关紧要”的做法吗?

在某种程度上,很多无关紧要。审查您的代码并适应您的团队。这通常是正确的事情。如果团队中的每个人都希望以某种方式进行编码,那么最好以这种方式进行(与自己的一群人相比,改变一个人(自己)所需要的故事点更少)。

这是惯例吗?

我不记得曾经看到一个空的分支。不过,我确实看到人们添加了属性以避免求反。


0

我仅要解决问题的第二部分,这是基于我在工业系统中工作和在现实世界中操作设备的观点。

但是,从某种程度上来说,这是扩展的评论,而不是答案。

注明时

其次,最好测试真实值,而不是错误。这意味着最好测试“ doorClosed”变量而不是“!doorOpened”变量

他的观点是,这使代码的工作更加清晰。

从我的角度来看,这里假设门状态是二进制状态,而实际上至少是三元状态:

  1. 门是开着的。
  2. 门既没有完全打开也没有完全关闭。
  3. 那扇门是关着的。

因此,根据单个二进制数字传感器的位置,您只能推测以下两个概念之一:

  1. 如果传感器在门的打开侧:门是打开的还是未打开的
  2. 如果传感器在门的关闭侧:门已关闭或未关闭。

而且,您不能通过使用二进制否定来互换这些概念。因此doorClosed!doorOpened可能不是同义词,并且任何假装它们是同义词的尝试都是错误的假设,认为系统状态的知识要比实际存在的知识更多。

回到您的问题,我将支持与变量表示的信息来源相匹配的语言。因此,如果信息是从门的关闭侧得出的,则继续doorClosed等等。这可能意味着根据需要使用各种陈述中的一种doorClosed!doorClosed多种,从而可能导致使用否定词的混乱。但是它没有做的是隐式传播关于系统状态的假设。


为了便于进行讨论,我所掌握的有关系统状态的信息量取决于整个系统本身所需的功能。

有时我只需要知道门是否关闭。在这种情况下,只有一个二进制传感器就足够了。但是在其他时候,我确实需要知道门是打开,关闭还是正在转换中。在这种情况下,要么有两个二进制传感器(在门极运动的每个极限点,同时检查门是否同时打开和关闭就进行错误检查),要么有一个模拟传感器来测量门的“打开”程度。

第一个例子是微波炉的门。您可以根据门是否关闭来启用烤箱操作。您不在乎门如何打开。

第二个例子是简单的电机驱动致动器。当执行器完全耗尽时,可以禁止向前驱动电动机。当执行器完全插入时,您可以禁止反向驱动电动机。

从根本上讲,传感器的数量和类型归结为对传感器的成本进行分析,而不是对实现所需功能所需的需求进行分析。


“从我的观点出发,这里假设门状态实际上是至少三元状态,而门状态是二进制状态:”“您可以根据门是关闭还是不关闭来启用烤箱的操作。你不在乎门有多开。” 彼此矛盾。另外,我认为问题根本不在于门和传感器。
Sanchises

@Sanchises语句与上下文无关,因此并不矛盾。第一个陈述是在上下文中,三元状态的两个相对的二进制测量值不能通过二进制取反互换。第二种说法是在上下文中,只有三元状态的部分知识可能足以使应用程序正常工作。至于门,OP询问是否打开和关闭了门。我只是指出一个可能影响数据处理方式的明显假设。
Peter M

-1

具体的样式规则总是不好的。指导原则是好的,但是最后,在很多情况下,您可以通过做一些不完全遵循指导原则的事情来使事情变得更清晰。

就是说,人们非常讨厌空无一物的“浪费行”,“多余的打字”,这是很糟糕的。如果确实需要垂直空间,则可以提出将方括号移到同一行的论点,但是如果这是一个问题,则无论如何都不应将{放在单独的行中。

如在其他地方提到的,具有else块对于显示您明确希望在其他情况下什么也不发生非常有用。经过大量的函数式编程(需要执行其他操作)之后,我了解到,编写@if时应始终考虑else,尽管正如@OldCurmudgeon所提到的,实际上有两种不同的用例。一个人应该有另一个,不应该。可悲的是,这不是您总能一目了然的事情,更不用说棉短绒了,因此,教条主义的“总是把另一个障碍”。

至于“没有负面影响”,绝对规则是错误的。有一个空的if可能会很奇怪,尤其是如果那是if的类型而不需要else的话,那么就写所有这些而不是一个!。或== false不好。就是说,在很多情况下,否定都是有意义的。一个常见的例子是缓存一个值:

static var cached = null

func getCached() {
    if !cached {
        cached = (some calculation, etc)
    }

    return cached
}

如果实际(思想/英语)逻辑涉及否定,则if语句也应如此。

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.