代码之家  ›  专栏  ›  技术社区  ›  rubenvb

“if(…)return…”;没有“else”被认为是好的风格吗?[关闭]

  •  18
  • rubenvb  · 技术社区  · 14 年前

    此代码:

    if( someCondition )
        return doSomething();
    
    return doSomethingElse();
    

    与此代码相比:

    if( someCondition )
        return doSomething();
    else
        return doSomethingElse();
    

    本质上,它们是一样的,但是什么是最好的风格/性能/。。。(当然,答案中是否有非自以为是的部分)?同时考虑多个“if else”的情况:

    if( someCondition )
        return doSomething();
    else if( someOtherCondition )
        return doSomethingDifferently();
    //...
    else
        return doSomethingElse();
    

    谢谢!

    5 回复  |  直到 14 年前
        1
  •  45
  •   John Dibling    14 年前

    当函数中有多个返回语句时,这称为“早期返回” Google search 对于“提前返回”,你会发现一个接一个的链接说这是不好的。

    我胡说。

    有两个主要原因和一个次要原因,人们声称早期回报是不好的。我会仔细检查,然后依次提出我的反驳。记住,这是我的全部意见,最终你必须自己决定。

    1)原因:提前退货,清理困难。

    反驳:这就是 RAII 是为了。一个设计良好的程序不会以这样的方式分配资源:如果执行提前离开作用域,这些资源就会泄漏。而不是这样做:

    ...

    int foo()
    {
      MyComplexDevice* my_device = new MyComplexDevice;
      // ...
      if( something_bad_hapened )
        return 0;
      // ...
      delete my_device;
      return 42;
    }
    

    你这样做:

    int foo()
    {
      std::auto_ptr<MyComplexDevice> my_device(new MyComplexDevice);
      if( something_bad_hapened )
        return 0;
      // ...
      return 42;
    } 
    

    提前返回不会造成资源泄漏。在大多数情况下,您甚至不需要使用 auto_ptr 因为您将创建数组或字符串,在别致的情况下,您将使用 vector , string 或者类似的东西。

    无论如何,您应该这样设计您的代码以保证健壮性,因为可能会出现异常。异常是早期返回的一种形式,就像显式 return 声明,你需要准备好处理它们。您不能在中处理异常 foo() ,但是 福() 无论如何都不应该泄漏。

    2)原因:早期返回使代码更加复杂。 反驳:早期返回实际上使代码更简单。

    职能应该有一个责任,这是一个共同的哲学。我同意。但是人们对此太过分了,认为如果一个函数有多个返回,它必须有多个责任。(他们说函数的长度不应该超过50行,或者其他任意的数字)我说不。仅仅因为一个函数只有一个职责,并不意味着它没有太多的事情来完成这个职责。

    以打开数据库为例。这是一种责任,但它由许多步骤组成,每个步骤都可能出错。打开连接。登录。获取连接对象并返回它。3个步骤,每个步骤都可能失败。您可以将其分解为3个子步骤,但不要使用这样的代码:

    int foo()
    { 
      DatabaseObject db = OpenDatabase(...);
    }
    

    你最终会得到:

    int foo()
    {
      Connection conn = Connect(...);
      bool login = Login(...);
      DBObj db = GetDBObj(conn);
    }
    

    所以你真的把多个职责移到了调用堆栈的更高点。

    3)原因:多个返回点不是面向对象的。 反驳:这其实只是另一种说法,“每个人都说多重回报是糟糕的,尽管我不知道为什么。”

    换一种说法,这实际上只是把所有东西塞进一个物体形状的盒子里,即使它不属于那里。当然,也许连接是一个对象。但是是登录吗?登录尝试不是(IMO)对象。这是一次行动。或者一个算法。尝试采用这种算法并将其塞进一个对象形状的框中是一种徒劳的OOP尝试,只会导致代码更复杂、更难维护,甚至可能效率更低。

        2
  •  8
  •   Puppy    14 年前

    函数应该总是尽快返回。这节省了不必要语句中的语义开销。尽快返回的函数提供了最清晰、最干净、最可维护的源代码。

    当你不得不手工编写SESE风格的代码来释放你分配的每一个资源时,记住在几个不同的地方释放它们是一种浪费。现在我们有了RAII,但是,它绝对是多余的。

        3
  •  3
  •   fredoverflow    14 年前

    这纯粹是个人喜好或编码标准的问题。就我个人而言,我更喜欢第三种变体:

    return someCondition ? doSomething() : doSomethingElse();
    
        4
  •  3
  •   Kiril Kirov    14 年前

    这要看情况,我喜欢和弗雷德弗洛夫一样

    return someCondition ? doSomething() : doSomethingElse();
    

    如果这足够的话。如果不是,我想知道类似的情况-如果你有更长的代码-让我们说30-40行或更多,我应该把 return; 在一个地方,那是不必要的。例如,考虑以下情况:

    if( cond1 )
    {
        if( cond2 )
        {
             // do stuff
        }
        else if( cond3 )
        {
            // ..
        }
    } 
    else if( cond4 )
    {
        // ..
    }
    else
    {
        //..
    }

    回报; (在void函数中)在每种情况的结尾-这是一种好的还是坏的编码风格(因为这与 回报; 或者不)。最后我决定把它放在这里,因为开发人员,稍后会阅读这段代码,知道这是一个最终状态,在这个函数中没有任何事情要做了。如果他/她只在这种情况下感兴趣,就不要读代码的其余部分。

        5
  •  -1
  •   Cheers and hth. - Alf    14 年前

    这要看情况。

    如果你遵循早期返回的惯例来处理错误情况,那么这是好的,如果你只是做任意的事情,那么这是坏的。

    出现的代码最严重的问题是没有使用大括号。这意味着不太明白什么是清晰。如果不是这样的话,我会用“清晰的目标”来回答你的主要问题,但首先你需要明白清晰。作为这条路的第一步,开始使用花括号。尽量让别人能读懂你的代码,这样别人(或数月/年后的你自己)一眼就能看懂。

    干杯。,