多个组合逻辑判断是 if else 更合理 还是 goto 最后输出之前更合理? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
l1905
V2EX    PHP

多个组合逻辑判断是 if else 更合理 还是 goto 最后输出之前更合理?

  •  
  •   l1905 2015-09-01 10:31:27 +08:00 6878 次点击
    这是一个创建于 3698 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比方有如下两种例子

    第一种写法

    function a () { if ($is_pass_1 ) { if ($is_pass_2 ) { if ($is_pass_3 ) { //... //业务代码处理 return result; } } } } 

    第二种写法

    function b () { if (!$is_pass_1 ) { //逻辑处理 goto xxxxx; } if (!$is_pass_2 ) { //逻辑处理 goto xxxxx; } if (!$is_pass_3 ) { //逻辑处理 goto xxxxx; } //业务代码处理 xxxxxx: #goto 到的位置 // result = return result } 
    第 1 条附言    2015-09-01 12:57:13 +08:00

    之前我可能描述的不清楚, 现在补充下

    1. $is_pass_1, $is_pass_2, $is_pass_3 等不是平级的,自然是不适用 switch

    2. 每个判断之后可能都会有部分逻辑处理

    3. if 之后同样存在 else 语句

    4. 目前遵循 同一个方法, 只有最后一个出口

    5. 业务复杂后,虽然提取了公共的方法, 但依然存在很多 判断组合

    我调整后的代码结构

    第一种

    function a() { if($is_pass_1) { //部分逻辑 if($is_pass_2) { //部分逻辑 if($is_pass_3) { //... //业务代码处理 result = 'balbalbalbal'; } else { //else 逻辑 } } else { //else 逻辑 } } else { //else 逻辑 } return result; } 
    第 2 条附言    2015-09-01 13:21:19 +08:00

    调整后的第二种写法

    function b() { if(!$is_pass_1) { //逻辑处理 goto xxxxx; } //逻辑处理 if(!$is_pass_2) { //逻辑处理 goto xxxxx; } //逻辑处理 if(!$is_pass_3) { //逻辑处理 goto xxxxx; } //逻辑处理 //业务代码处理 xxxxxx: #goto 到的位置 // result = return result } 
    61 条回复    2015-09-03 13:41:24 +08:00
    est
        1
    est  
       2015-09-01 10:32:40 +08:00
    php 里难道没有 else if ?
    niinaranpo
        2
    niinaranpo  
       2015-09-01 10:32:49 +08:00
    为什么不用 switch
    feiyuanqiu
        3
    feiyuanqiu  
       2015-09-01 10:34:44 +08:00
    逻辑运算符哭晕在厕所...
    function a () {
    if ($is_pass_1 && $is_pass_2 && $is_pass_3 ) {

    }
    }
    luban
        4
    luban  
       2015-09-01 10:36:15 +08:00
    这 2 段代码不等价,实现功能不一样
    michaelzlies
        5
    michaelzlies  
       2015-09-01 10:36:42 +08:00   1
    l1905
        6
    l1905  
    OP
       2015-09-01 10:37:13 +08:00
    @est 这些不是平级 的 if else
    l1905
        7
    l1905  
    OP
       2015-09-01 10:45:03 +08:00
    @feiyuanqiu 每个判断条件后 都会有部分逻辑处理, 上面我可能写的不太清楚
    huijiewei
        8
    huijiewei  
       2015-09-01 10:52:16 +08:00
    一个很方便的准则就是

    尽早返回。。。

    业务逻辑再理一理吧。 goto 这种东西不用也罢
    poorguy
        9
    poorguy  
       2015-09-01 10:55:42 +08:00
    不清楚你具体业务,不过应该可以错误的先退出
    ```php
    function b () {
    if (!$is_pass_1 ) {
    //不成立的逻辑处理
    return;
    }
    //成立的逻辑处理
    ```
    morefreeze
        10
    morefreeze  
       2015-09-01 11:09:58 +08:00
    你可以用

    ```php
    do{
    if (!$cond1 ) break;
    if (!$cond2 ) break;
    while (0 );
    ```

    来避免掉 goto ,虽然你现在用 goto 都只是往下跳的,但你不保证之后别人修改你代码会怎么样理解这段呢
    l1905
        11
    l1905  
    OP
       2015-09-01 11:10:39 +08:00
    @huijiewei 呃呃呃。。 goto 到最后 应该就是遵循的尽早返回。没找到 goto 在目前逻辑下太不合理的地方
    l1905
        12
    l1905  
    OP
       2015-09-01 11:14:30 +08:00
    @poorguy 目前遵循的是复杂逻辑下只有一个出口
    otakustay
        13
    otakustay  
       2015-09-01 11:17:33 +08:00
    公用逻辑抽成另一个函数在各分支里调用就行,别用 goto
    qian19876025
        14
    qian19876025  
       2015-09-01 11:19:43 +08:00
    合适就行 为嘛一定要与趋势作对
    alphonsez
        15
    alphonsez  
       2015-09-01 11:26:11 +08:00
    goto 挺好的,尤其 C 错误处理的时候。
    ether
        16
    ether  
       2015-09-01 11:50:01 +08:00
    function a () {
    xxxxxx: #goto 到的位置
    // result =
    return result

    }

    function b () {
    if (!$is_pass_1 ) {
    //逻辑处理
    return a ();
    }
    if (!$is_pass_2 ) {
    //逻辑处理
    return a ();
    }
    if (!$is_pass_3 ) {
    //逻辑处理
    return a ();
    }
    //业务代码处理

    xxxxxx: #goto 到的位置
    return a ();
    }
    ibremn
        17
    ibremn  
       2015-09-01 11:52:12 +08:00
    举个 C 的例子吧。。
    下面的函数是把图片数据解压成 iOS 可以直接显示的 Bitmap 。。。

    第一种是遵循了"尽早返回"的原则。。。


    第二种是用了 goto 。。。


    在某些情况下,适当地用 goto 还是不错的,只要注意别出现 goto fail; goto fail; 这种 bug 就好蛤蛤蛤。。。
    pathletboy
        18
    pathletboy  
       2015-09-01 11:54:47 +08:00
    可以用 do while (0 );就别用 goto 了。
    flowfire
        19
    flowfire  
       2015-09-01 12:16:32 +08:00
    @pathletboy do while (0 ) 什么鬼
    ljbha007
        20
    ljbha007  
       2015-09-01 12:21:44 +08:00
    switch case 就是为这种情况准备的啊
    FrankFang128
        21
    FrankFang128  
       2015-09-01 12:24:26 +08:00
    你应该优化逻辑,不要出现这么多 if
    hitmanx
        22
    hitmanx  
       2015-09-01 12:24:29 +08:00   1
    想起了 Dijkstra 大神的那篇可能是最著名的文章<Go To Statement Considered Harmful>
    zacard
        23
    zacard  
       2015-09-01 12:53:13 +08:00
    优化逻辑,优先返回。
    kobe1941
        24
    kobe1941  
       2015-09-01 13:10:38 +08:00
    从开始学编程,所有的人包括老师和书籍都不让用 goto
    msg7086
        25
    msg7086  
       2015-09-01 13:13:58 +08:00
    @flowfire do while 0 给你机会用 break 。

    另外 Ruby 里推荐的方式是用 throw/catch 来解决。 C++/Java/PHP 的话也可以考虑用这种方法,比较干净。
    当然最好的方法肯定是拆函数,只有实在不适合拆函数的时候才考虑 goto 。
    narcotics
        26
    narcotics  
       2015-09-01 13:37:43 +08:00
    @msg7086 利用异常机制表达逻辑或许不是个好主意?
    akagi
        27
    akagi  
       2015-09-01 13:48:29 +08:00
    个人觉得可以试试表驱动?
    21grams
        28
    21grams  
       2015-09-01 14:01:02 +08:00
    goto 也可以适当的用一下,怕啥,不就是只恐龙嘛。
    msg7086
        29
    msg7086  
       2015-09-01 14:12:23 +08:00
    @narcotics Ruby 里的异常是 raise/rescue 。 throw/catch 就是用来抛球接球的。

    另外其实这种结构也算是异常。
    undef404
        30
    undef404  
       2015-09-01 14:30:31 +08:00
    @msg7086

    c++里面不推荐用异常来做逻辑控制
    l1905
        31
    l1905  
    OP
       2015-09-01 15:06:30 +08:00
    @kobe1941 我也"从开始学编程,所有的人包括老师和书籍都不让用 goto" ,但遇到具体业务逻辑的用它的时候, 却没想到强有力不用它的理由,或者说是列不出用 goto 有哪些不能容忍的缺点
    hitmanx
        32
    hitmanx  
       2015-09-01 15:13:38 +08:00   1
    @l1905 如果功能简单的话确实没什么。不过假如未来这个函数的功能随着迭代更新变得越来越长,越来越复杂,加之如果后续维护的人并不是当初编写者时,就很容易出各种各样的问题,因为 goto 语句破坏了结构性。即使你现在很清楚你在干什么,也不保证后续模仿你的风格继续增加 goto 语句的人也像你这样清晰,一点小看法。
    leoe
        33
    leoe  
       2015-09-01 16:04:50 +08:00
    我觉的这个逻辑用 goto 处理很好啊,代码更简洁、更易读。 linux 内核里有很多 goto 啊,尤其是逻辑块多,函数返回前还需要一些处理时,用 goto 很方便。
    computeramber
        34
    computeramber  
       2015-09-01 16:26:32 +08:00
    测试 crawl = =!
    cxbig
        35
    cxbig  
       2015-09-01 20:31:20 +08:00
    twi3325831
        36
    twi3325831  
       2015-09-01 21:40:53 +08:00
    楼主试过这种写法没

    function b () {
    do {
    if (!$is_pass_1 ) {
    //逻辑处理
    break;
    }
    //逻辑处理
    if (!$is_pass_2 ) {
    //逻辑处理
    break;
    }
    //逻辑处理
    if (!$is_pass_3 ) {
    //逻辑处理
    break;
    }
    //逻辑处理

    //业务代码处理
    } while (0 );

    // 错误处理
    // result =
    return result;
    }
    dorentus
        37
    dorentus  
       2015-09-01 22:13:30 +08:00
    说句题外话, Swift 2 为了支持尽早返回,提供了 guard 关键字来尽早返回,然后提供了 defer 关键字来解决返回导致的无法集中释放资源的问题。
    asj
        38
    asj  
       2015-09-01 22:14:50 +08:00 via iPad
    有些时候,看起来似乎今天一个程序员为软件写了 10 行代码,
    其实他写了-1000 行代码
    2015813
        39
    2015813  
       2015-09-01 22:47:58 +08:00 via Android
    大师云:果断 if ,抛弃 goto ,它会让你晕头转向。
    raincious
        40
    raincious  
       2015-09-01 23:07:07 +08:00
    看了楼主的 Append 之后再看原来的,觉得一二两种方案的区别基本上就是第二种会被打更惨而已……

    重构成这样应该就好多了:
    https://gist.github.com/raincious/c2845e414d62832db861
    cpper
        41
    cpper  
       2015-09-01 23:23:01 +08:00   1
    对于 if else 这种判断的,请进行读表形式处理。代码大全有类似介绍
    flowfire
        42
    flowfire  
       2015-09-02 03:17:03 +08:00
    @msg7086 不是应该是 do while 1 么、、、
    msg7086
        43
    msg7086  
       2015-09-02 05:39:04 +08:00
    @flowfire do while 1 就变成死循环了。
    vibbow
        44
    vibbow  
       2015-09-02 06:14:24 +08:00
    try
    {
    if ( ! aaaa )
    {
    throw new Exception ('aaa');
    }


    if ( ! bbb )
    {
    throw new Exception ('bbb');
    }
    }
    catch (Exception $e )
    {

    }
    flowfire
        45
    flowfire  
       2015-09-02 06:57:24 +08:00
    @msg7086
    do while 0
    就是只执行一次没什么卵用
    do while 1
    就是无限循环知道满足条件用 break 跳出。。
    有哪里不对么。。
    zhczhy
        46
    zhczhy  
       2015-09-02 08:21:28 +08:00
    允许用 goto 就 goto ,不允许时大部分情况下都可以 do { ... } while (0 )
    V2 上还是得多一些这样的纯技术讨论帖
    bdnet
        47
    bdnet  
       2015-09-02 08:27:02 +08:00
    有个叫 switch case

    更好的方式可以用字典,如果所用编程语言支持委托的话。

    goto 很容易造成死循环
    msg7086
        48
    msg7086  
       2015-09-02 08:27:57 +08:00
    @flowfire 你自己好好动脑筋想想吧……不想多吐槽了。
    romisanic
        49
    romisanic  
       2015-09-02 09:09:54 +08:00
    @ibremn
    不过不管公司要求还是自己写代码,还是尽量避免在一个方法中有过多的 return 。。。
    mcfog
        50
    mcfog  
       2015-09-02 09:22:02 +08:00
    别说 goto 了,我连 else 都不想看到,尤其是一眼看不完的()里的条件或超过 3 行的{}里的代码。战术上提前 return ,抽函数,查表什么的方法有的是,战略上说穿了就是自己其实压根没想清楚就在写代码了,自然写的一手好面条
    Mysdes
        51
    Mysdes  
       2015-09-02 09:36:29 +08:00
    在我还是个程序猿的时候,老师千叮咛万嘱咐,如果没人把刀架你脖子上,能别 goto 就别 goto ,哈哈哈
    lizhiqing1996
        52
    lizhiqing1996  
       2015-09-02 09:39:06 +08:00   1
    @flowfire do while 0 只执行一次,满足一定条件可以退出 while 代码块,从而实现了 goto 的功能。如果一直不退出 while 代码块,则 while 代码块里的语句只会执行一次,效果就和没用 while 一样,不会影响代码运行


    @msg7086 不知道我说得对不
    lizhiqing1996
        53
    lizhiqing1996  
       2015-09-02 09:41:06 +08:00
    我怎么看都感觉你的两串代码实现的是不一样的功能,不管是修改前或修改后...
    mornlight
        54
    mornlight  
       2015-09-02 09:42:52 +08:00
    @romisanic 这个很奇怪,许多地方是推荐多用 return 少用嵌套 if else 来明确表示方法结束和返回值,代码可读性更高。
    myv2ex
        55
    myv2ex  
       2015-09-02 10:30:27 +08:00
    尝试利用面向对象的思想, 3 个条件非平级,则必定存在引用包含关系,那么可通过定义基本模型关系,再通过接口注入模型对象到处理模型的操作对象,操作对象中根据业务逻辑定义处理各模型的不同逻辑完成继承关系,通过覆写操作取代过程化的代码处理机制,后期随着业务模型对象的增加,也仅仅是完善模型接口定义及方法而已,对今后代码发展具有积极作用。
    WordCount
        56
    WordCount  
       2015-09-02 11:06:34 +08:00 via Android
    @akagi +1 这才是正解
    soundofu
        57
    soundofu  
       2015-09-02 13:51:40 +08:00
    LZ 的第二种写法作为错误处理的时候也未尝不可,
    实际使用中,我采用的更接近 @ibremn 所说的尽早 renturn 。
    skydiver
        58
    skydiver  
       2015-09-02 13:59:00 +08:00
    @myv2ex Java 写多了吧兄弟……
    Banio
        59
    Banio  
       2015-09-02 14:04:48 +08:00
    当年学 C 语言的时候 说不推荐用 goto 。。。然后一直我就没用过
    ffffwh
        60
    ffffwh  
       2015-09-02 15:30:26 +08:00
    有限状态自动机
    zonghua
        61
    zonghua  
       2015-09-03 13:41:24 +08:00
    Javascript 没有 goto,好像也不建议用 switch
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3218 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 11:27 PVG 19:27 LAX 04:27 JFK 07:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86