为什么空的 else-if 语句是不良风格,我应该如何重写它?

huangapple go评论70阅读模式
英文:

Why is an empty else-if statement bad style, and how should I rewrite it?

问题

自动评分我的代码的程序正在扣我“风格分”,因为一个没有执行任何代码的 else-if。它说这可能会导致错误,但我认为不会。

我不确定如何更改它以使其仍然起作用,但又不违反规则。为什么这样做不好?我认为我以其他任何方式编写它,读者都会更难理解。应该如何改写?

if (!seesWater(LEFT))
{
    turn(LEFT);
}
else if (!seesWater(AHEAD))
{
    // Do nothing here
}
else if (!seesWater(RIGHT))
{
    turn(RIGHT);
}
else
{
    turn180();
}

之所以存在没有执行任何操作的 else-if,是因为我希望代码按照特定的优先级进行操作:

如果 (!seesWater(AHEAD)),那么我不希望其余的条件运行,因为它们不重要。

英文:

The program that automatically grades my code is docking me "style-points" for an else-if that doesn't execute any code. It says that it may cause an error, but I don't think it could.

I'm not sure how to change it so that it still works but doesn't break the rule. Why is doing this bad form? I think any other way I write it will be harder for a reader to understand. How should it be written instead?

if (! seesWater(LEFT))
{
    turn(LEFT);
}
else if (! seesWater(AHEAD));
else if (! seesWater(RIGHT))
{
    turn(RIGHT);
}
else
{
    turn180();
}

The reason the else-if is there but does nothing is because of the priority in which I want the code to act:

if (! seesWater(AHEAD)), then I don't want the rest of the conditions to run at all because they don't matter.

答案1

得分: 143

谁说这是“不好的风格”?

要问的相关问题是,这是否比其他选择更清晰?在你的特定情况下,我会说是的。这段代码清楚地表示在4个选项之间进行选择,其中一个选项是“什么都不做”。

我唯一会做的更改是将那个相当微不足道的分号替换为一对空的大括号,可能还附加一个注释,以明确表示这不是一个错误。

if (!seesWater(LEFT)) {
    turn(LEFT);
}
else if (!seesWater(AHEAD)) {
    // 无需操作
}
else if (!seesWater(RIGHT)) {
    turn(RIGHT);
}
else {
    turn180();
}

这并不是在一般情况下支持“空语句块”作为可以接受的风格;仅仅是应该根据情况进行争论,而不是基于某些必须遵守的规则。这是培养良好品味的问题,品味的判断应该由人类做出,而不是毫无意识的自动化工具。

英文:

Who says it's "bad style"?

The relevant question to ask is, is this clearer than alternatives? In your specific case, I'd say it is. The code clearly expresses a choice between 4 options, of which one is "do nothing".

The only change I'd make is to replace that rather insignificant semicolon by an empty pair of braces, possibly with a comment to make it clear it's not a mistake.

if (! seesWater(LEFT)) {
    turn(LEFT);
}
else if (! seesWater(AHEAD)) {
    // nothing required
}
else if (! seesWater(RIGHT)) {
    turn(RIGHT);
}
else {
    turn180();
}

This is not endorsing 'empty clauses' as a generally-acceptable style; merely that cases should be argued on their merits, not on the basis of some Rule That Must Be Obeyed. It is a matter of developing good taste, and the judgement of taste is for humans, not mindless automata.

答案2

得分: 45

如果这是您想要的逻辑,您的代码没有问题。在代码风格方面,我同意其他用户的意见。我个人认为,像这样的代码会更清晰一些:

if not seesWater(LEFT):
    turn(LEFT);
elif not seesWater(AHEAD):
    # 什么都不做
elif not seesWater(RIGHT):
    turn(RIGHT);
else:
    turn180();

但是,通过优先选择左转而不是前进(什么都不做),运动可能会陷入循环中:

(图片)

如果您希望运动“什么都不做”,但避免进入水域,类似这样:

(图片)

您可能希望将逻辑更改为类似这样的内容:

if not seesWater(AHEAD):
    # 什么都不做,继续前进
elif not seesWater(LEFT):
    turn(LEFT);
elif not seesWater(RIGHT):
    turn(RIGHT);
else:
    turn180();

希望对您有所帮助。

英文:

If this is the logic you want, there is nothing wrong with your code. In terms of code styling wise, I agree with the other users. Something like this would be clearer in my opinion:

if (! seesWater(LEFT))
{
    turn(LEFT);
}
else if (! seesWater(AHEAD))
{
    //Do nothing
}
else if (! seesWater(RIGHT))
{
    turn(RIGHT);
}
else
{
    turn180();
}

But by having priority of making a left turn over moving ahead (by doing nothing), the movement may end up in circles:

为什么空的 else-if 语句是不良风格,我应该如何重写它?

If you want the movement to "do nothing" but avoid moving into waters like this:

为什么空的 else-if 语句是不良风格,我应该如何重写它?

You may want to change your logic to something like this:

if (! seesWater(AHEAD))
{
    //Do nothing. Keep moving
}
else if (! seesWater(LEFT))
{
    turn(LEFT);
}
else if (! seesWater(RIGHT))
{
    turn(RIGHT);
}
else
{
    turn180();
}

答案3

得分: 26

你可以反转 ! seesWater(AHEAD) 条件。然后,你可以将其 else 子句中的代码移到其 if 子句中:

if (seesWater(LEFT))
{
    turn(LEFT);
}
else if (!seesWater(AHEAD)) 
{
    if (seesWater(RIGHT))
    {
        turn(RIGHT);
    }
    else
    {
        turn180();
    }
}
英文:

You can invert the ! seesWater(AHEAD) condition. Then you can move the code in its else clause to its if clause:

if (! seesWater(LEFT))
{
    turn(LEFT);
}
else if (seesWater(AHEAD)) 
{
    if (! seesWater(RIGHT))
    {
        turn(RIGHT);
    }
    else
    {
        turn180();
    }
}

答案4

得分: 13

我会认为你可以决定不改变代码的逻辑。我认为没有理由避免空的ifelse if代码块,如果这会使你的代码变得更可读,逻辑更易理解的话。通常你可以重写代码,不包含空的代码块,但仍然能保持其易于理解。但如果不能,我认为也是可以的。

不过有一点...我不喜欢使用;来表示空的代码块的风格。那很容易被忽视,通常不会出现,所以可能会让读者感到困惑。我建议将替换为一对空的花括号。你也可以在空的花括号内部放置注释,以清楚地表明你希望该代码块是空的,比如// 在这种情况下,我们不需要做任何事情

英文:

I would argue that you can decide to not change the logic of your code at all. I think there's no reason to avoid an empty if or else if block if that leads to your code being the most readable and the logic most understandable. You can often rewrite your code to not include an empty code block and yet have it be just as understandable. But if not, I say this is fine.

One thing though...I don't like the style of using a ; to denote an empty code block. That's really easy to miss and is not normally seen, so it can confuse the reader. I'd suggest replacing the ; with an empty set of curly braces. You could also put a comment inside the empty curlies to make it clear you mean for that code block to be empty, ie // In this case, we don't want to do anything.

答案5

得分: 13

针对这段特定的代码示例,我认为逻辑不准确,也不直观。看起来你想要在前方有水的情况下执行某些操作... 但是左转的部分让人感到困惑,可能是个错误。最终,我认为这个空逻辑是一个双重否定,即“如果前方没有水,就不执行任何操作”,而双重否定也是不推荐的。

if (seesWater(AHEAD))
{
    if (! seesWater(LEFT))
    {
        turn(LEFT);
    }
    else if (! seesWater(RIGHT))
    {
        turn(RIGHT);
    }
    else
    {
        turn180();
    }
}

这样做是最合理的,因为额外的逻辑是基于前方是否有水。如果前方有水,这样做也会更容易,如果想要将这些操作移动到另一个函数中。

英文:

For this particular code sample, I don't believe the logic is accurate and does not flow intuitively. It looks like you want to turn if there is water ahead...but that left turn is in there that makes it confusing and potentially a bug. Ultimately I see the empty logic as a double negative, 'if there is no water ahead, do nothing', and double negatives are also frowned upon.

if (seesWater(AHEAD))
{
    if (! seesWater(LEFT))
    {
        turn(LEFT);
    }
    else if (! seesWater(RIGHT))
    {
        turn(RIGHT);
    }
    else
    {
        turn180();
    }
}

This makes the most sense since the additional logic is based on whether there is water ahead. It also makes it easier if you want to move the actions to another function if there is water ahead.

答案6

得分: 13

我发现在 if(!condition) 语句中使用的负向逻辑很难阅读和令人费解,尤其是与 if-else-else-else 结合使用时更是如此。我更喜欢使用正向逻辑,比如 seesLand() 而不是 !seesWater

你可以修改 turn() 函数,让 turn(AHEAD) 什么也不做,而 turn(BACK) 则执行180度转身,而无需为此编写单独的函数。

然后你可以将其改写为:

List<Direction> directions = new ArrayList(LEFT, FORWARD, RIGHT, BACK);
for (Direction d: directions) {
    if (seesLand(d)) {
        turn(d);
        return;
    }
}

一个优势是这样更加通用化。你可以通过定义另一个数组,按照希望的顺序排列方向,从而轻松创建不同的移动策略,并将它们传递给此函数以按选定顺序检查和转向。

英文:

I find the negative logic in the if(!condition) statements hard to read and mind-twisting, even more so in combination with if-else-else-else. I would prefer a positive logic like seesLand() rather than !seesWater.

You could modify the turn() function, so that turn(AHEAD) does nothing and turn(BACK) does the 180 turn instead of needing a separate function for that.

Then you could rewrite this into.

List&lt;Direction&gt; directions = new ArrayList(LEFT, FORWARD, RIGHT, BACK);
for (Direction d: directions) {
    if(seesLand(d) {
        turn(d);
        return;
}

One upside is that this generalises even more. You could create different movement strategies simply by defining another array where you order the directions as you wish, and feed them into this function to check and turn in the chosen order.

答案7

得分: 10

你对这样的情况进行的操作是将其转化为一个语音方法,最好是将其拆分。

选项1:

private void 转向地面(){
  if(! 看见水(前方)){
    return;
  }
  if (! 看见水(左侧))
  {
     转向(左侧);
     return;
  }
  if (! 看见水(右侧))
  {
    转向(右侧);
    return;
  }
  转向180度();
}

选项2:

private 方向 确定移动方向(){
  if(! 看见水(前方)){
    return 前方;
  }
  if (! 看见水(左侧))
  {
     return 左侧;
  }
  if (! 看见水(右侧))
  {
    return 右侧;
  }
  return 后方;
}

然后像这样使用选项2:

方向 移动方向 = 确定移动方向();
转向(移动方向);

为什么?因为方法名称使代码的意图清晰。并且早期返回允许快速阅读,在一个条件适用时我们不需要阅读整个if-else代码来确保一旦一个情况适用就不会发生其他情况。此外,在选项2中,您对移动位置和实际转向有明确的关注分离,这有助于模块化,在这种情况下还允许在一个单独的位置记录最终决策,即您要转向的位置,例如。

另外,最好的情况是这些检查不会被否定,而会有一个“看见陆地”或“看见可访问的地块类型”的方法。在心理上,解析非否定语句更容易/更快,并且这使得您实际上正在寻找什么更清楚(即陆地块、冰块等)。

英文:

What you do with something like this is you turn it into a speaking method and preferably split it up.

Option 1:

private turnTowardsGround(){
  if(! seesWater(AHEAD){
    return;
  }
  if (! seesWater(LEFT))
  {
     turn(LEFT);
     return;
  }
  if (! seesWater(RIGHT))
  {
    turn(RIGHT);
    return;
  }
  turn180();
}

Option 2:

private determineMoveDirection(){
  if(! seesWater(AHEAD){
    return AHEAD;
  }
  if (! seesWater(LEFT))
  {
     return LEFT
  }
  if (! seesWater(RIGHT))
  {
    return RIGHT
  }
  return BACK;
}

and then use Option 2 like:

Direction directionToMove = determineMoveDirection();
turn(directionToMove);

Why? Because the method names make the intend of the code clear. And the early return exits allow a quick read where we don't need to read the whole if-else code to make sure nothing else happens once one case applies. Plus in the option 2 case you have a clear separation of concerns (finding out where to move to vs actually turning), which is nice for modularity and in this case also allows one single place to log the final decision where you're going to turn, for example.

Also, preferably the checks would not be negated but there would be a "seesLand" or "seesAccessibleFieldType" method. It's psychologically easier/faster to parse non-negated statements and it makes it more clear what you are actually looking for (i.e. a land tile, a ice tile, ...).

答案8

得分: 8

为什么一个空的if子句会被认为是不好的风格?因为这是一种不明显的方法来“退出”if块。它跳过了后续的else-if,并且更重要的是跳过了最后的else语句,而在多条件块中,最终的else语句实际上是“默认”操作。

对我来说,这里有两个主要问题:

  1. if语句的顺序很重要,但不清楚为什么选择了这个顺序。
  2. else语句似乎具有逻辑,但被do_nothing跳过,而不是成为一个通用情况。

我看到这样的代码时,首先要问的问题是为什么do_nothing选项((! seesWater(AHEAD)))不是我们检查的第一件事?是什么让! seesWater(LEFT)成为我们检查的第一件事?我希望能够看到关于为什么这个顺序很重要的评论,因为这些if语句似乎不明显是互斥的(在多个方向上都可能看到水)。

我会问的第二个问题是在什么情况下我们预计会进入通用的else语句。目前,turn180()是“默认”的操作,但我觉得如果由于某种原因在四周查找失败,回到你来时的方向不太像是默认的行为。

英文:

Why would an empty-if clause be bad style? Because it is a non-obvious way of 'exiting' the if block. It skips over subsequent else-ifs and more importantly skips the final else, which in a multi-condition block ends up as the 'default' action.

To me there are two major problems here:

  1. The if-statement order matters, but it's unclear why this order is chosen
  2. The else-statement appears to have logic, which is skipped by do_nothing rather than being a catch-all

The first question I'd ask looking at code like this is why is the do_nothing option (! seesWater(AHEAD)) not the first thing we check? What makes ! seesWater(LEFT) the first thing we check? I'd hope to see a comment as to why this order was important as the ifs don't seem to be obviously exclusive (could seeWater in multiple directions).

The second question I'd ask is in what cases we expect to end up in the catch-all else statement. At the moment turn180() is the 'default', but it doesn't feel like very default-y behaviour to me to go back the way you've come if looking around fails for some reason.

答案9

得分: 7

我来自C语言,且遵循MISRA标准,但对我而言,无论是否有"else"语句,带有分号的"if"语句都是不良的风格。原因是人们通常不会在那里加分号,除非是拼写错误。考虑以下代码:

if (!seesWater(AHEAD));
{
  stayDry();
}

在这段代码中,阅读代码的人会认为只有当你看不到前方的水时才会执行stayDry()函数 - 你必须仔细观察才能意识到它实际上会无条件地被调用。更好的做法是,如果你在这种情况下不想执行任何操作,可以使用花括号和注释:

if (!seesWater(AHEAD))
{
  /* 这里不需要做任何事情 */
}

事实上,无论是在"if"、"else"等子句的主体周围都应该始终加上花括号,即使子句只有一个单独的turn()调用也是如此!有时我会看到这样的代码:

if (!seesWater(AHEAD))
  stayDry();

然后稍后会有人添加其他内容:

if (!seesWater(AHEAD))
  stayDry();
  doSomethingElse();

当然,"doSomethingElse()"无论是否看到水,都会被执行,这不是第二个编写者的意图。你可能认为没有人会犯如此明显的错误,但实际上是会犯的。

英文:

I'm coming from C, and living with MISRA, but to me an "if" with a semicolon is bad style regardless of whether there is an "else". Reason is that people don't normally put a semicolon there unless it's a typo. Consider this:

if (! seesWater(AHEAD));
{
  stayDry();
}

Here someone reading the code will think that you only stayDry() if you don't see water ahead -- you have to look hard to see that it will actually be called unconditionally. Much better, if you don't want to do anything in this case, is curly brackets and a comment:

if (! seesWater(AHEAD))
{
  /* don&#39;t need to do anything here */
}

In fact putting the curly brackets around the body of the "if", "else" etc. should always be done, and good on you for using the curly brackets even when the clause is a single turn() call! I sometimes find code like

if (! seesWater(AHEAD))
  stayDry();

then someone will come along later and add something else:

if (! seesWater(AHEAD))
  stayDry();
  doSomethingElse();

and of course the Something Else is done whether you see water or not, which was not the second coder's intention. You may think no-one would make a mistake that is so obvious but they do.

答案10

得分: 5

代码部分不要翻译, 只返回翻译好的部分:

风格检查器报告某些内容为糟糕的风格的原因在于实施该风格检查器的人认为这是糟糕的风格。

你必须问他们为什么,他们的答案可能有道理,也可能没有。

对于任何需要人类智能的自动检查工具,都应该持谨慎态度。有时它们会产生有用的输出,而有时则不会。如果这样的检查器评估人类的工作,那将是非常不幸的,如果评估结果会产生后果,那将是极其不幸的。

英文:

The reason why a style checker reports something as poor style is that the people who implemented the style checker considered it poor style.

You'd have to ask them why, and their answer may, or may not, have merit.

Automated checkers of anything that require human intelligence should be treated with caution. Sometimes they produce useful output, and sometimes they don't. It's very unfortunate if such a checker is assessing the work of a human being, and extremely unfortunate if that assessment has consequences.

答案11

得分: 2

你对第二个 else if 语句没有进行任何操作,你应该将它重写为以下形式:

        else if (!seesWater(AHEAD)) {return }

这样程序就会有一个条件运算符来返回一个布尔语句,希望这能帮到你 -SG

英文:

You don't do anything with the 2nd else if statement you should rewrite it like this

        else if(!seesWater(AHEAD)){return }

This is so the program has a conditional operator to return a boolean statement hope this helps -SG

答案12

得分: 0

对我来说,这是避免以后忘记一个情况的一种方法,尤其是如果其中一些选项属于不同的类别。

// 如果忽略,则不执行任何操作
if(option=="red"){
    sound = "beep";
}else if(option=="blue"){
    sound = "beep";
}else if(option=="green"){
    sound = "long beep";
}else if(option=="ignore"){
    ; // 什么都不做
}

在这段代码中,忽略这种情况很难被遗忘,但如果没有它,结果将是相同的。

// 如果忽略,则不执行任何操作
if(option=="red"){
    sound = "beep";
}else if(option=="blue"){
    sound = "beep";
}else if(option=="green"){
    sound = "long beep";
}

然后,如果您决定希望所有颜色都发出相同的蜂鸣声,以简化代码,您可以这样做:

// 如果忽略,则不执行任何操作
sound = "beep";

这将适用于颜色,但如果忽略时也会将声音设置为蜂鸣声,而我们之前并没有这样做。"但是注释呢?"我听到你在问,好吧,在更长的代码中,您可能会忽略注释,而且可能会因为您可能只考虑颜色类别而忘记忽略情况[当然,自动化测试可以帮助您]。

因此,如果我从第一个版本开始,更难忽视它,而且我已经为忽略的情况有了一个if语句,所以我可以重新排列如下:

if(option=="ignore"){
    ; // 什么都不做
}else{
    sound = "beep";
}

或者

if(option!="ignore"){ sound = "beep"; }
英文:

For me it's a way to avoid forgetting a case later, especially if some of the options are different categories

// do nothing if ignoring
if(option==&quot;red&quot;){
    sound = &quot;beep&quot;
}else if(option==&quot;blue&quot;){
    sound = &quot;beep&quot;
}else if(option==&quot;green&quot;){
    sound = &quot;long beep&quot;
}else if(option==&quot;ignore&quot;){
    ; // do nothing
}

In that code case ignore is hard to forget however if you didn't have it, the outcome would be the same.

// do nothing if ignoring
if(option==&quot;red&quot;){
    sound = &quot;beep&quot;
}else if(option==&quot;blue&quot;){
    sound = &quot;beep&quot;
}else if(option==&quot;green&quot;){
    sound = &quot;long beep&quot;
}

then later if you decide that you want a the same beep for all colours so to simplify the code you could have

// do nothing if ignoring
sound = &quot;beep&quot;

which would work for the colors, but would also set sound to beep if ignoring, which we weren't doing previously. "But the comment", I hear you cry, well in longer code you might miss a comment and forget the ignore case because you might have been only thinking about the category of colours [of course automated testing can help you out]

So if I start from my first version it's harder to miss it, and I already have an if statement for the ignore case so I can rearrange

if(option==&quot;ignore&quot;){
    ; // do nothing
}else{
    sound = &quot;beep&quot;
}

Or

if(option!=&quot;ignore&quot;){ sound = &quot;beep&quot; }

答案13

得分: -1

好的,以下是您要求的翻译内容:

我们实际上并不了解整个问题的背景。我们不知道这是否是方法中唯一的代码。我不确定您为什么首先测试 LEFT。我认为您应该首先测试 AHEAD,因为我认为如果可能的话,您会继续沿着与默认方向相同的方向前进。如果您一直向左走,您将绕着圈子走。因此,考虑到缺乏要求,很难给出一个完整的答案。

然而,我倾向于不喜欢空的 if 语句。如果您想继续向前走,您需要以某种方式表明。

其他评论:

  1. 我更喜欢一个积极的方法名,比如 noWater(...)。然后,if 语句就变成了一个积极的测试,而不是一个否定的测试。

  2. 为什么您有多种形式的方法调用:turn(LEFT)turn(RIGHT)turn180()turn180() 为什么不同?我会创建一个可以接受任何方向参数的方法。

使用上述建议,您将会有类似以下的内容:

if (noWater(FORWARD))
    turn(0);
else if (noWater(LEFT))
    turn(270);
else if (noWater(RIGHT))
    turn(90);
else
    turn(180);

有了这样的结构,您就不会有空的 if 语句,移动变得参数化(而且明确),这样您可以根据需要使用不同的值。

英文:

Well we don't really know the context of the entire question. We don't know if this is the only code in a method. I'm not sure why you test for LEFT first. I would have thought you test for AHEAD first since I would think you continue in the same direction as the default if it is possible. If you keep going LEFT you will be walking in a circle. So given the lack of requirements it is hard to give a complete answer.

However, I would tend to agree that I don't like the empty if statement. If you want to keep walking AHEAD you need to indicate that somehow.

Other comments:

  1. I would rather have a positive method name like noWater(...). Then the if statement becomes a positive test instead of a negative test.

  2. Why do you have multiple forms of the method that you invoke: turn(LEFT), turn(RIGHT), and turn180()? Why is turn180() different? I would create a method that would accept a parameter for any direction.

Using the above suggestions you would have something like:

if (noWater(FORWARD))
    turn(0);
else if (noWater(LEFT))
    turn(270);
else if (noWater(RIGHT))
    turn(90);
else
    turn(180);

With a structure like this you don't have an empty if statement and the movement becomes parameterized (and explicit) so you can have different values as required.

huangapple
  • 本文由 发表于 2020年9月23日 09:13:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/64019647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定