V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
lhx2008
V2EX  ›  问与答

循环结束条件要不要写超集?有什么好处?

  •  
  •   lhx2008 · 2019-03-03 11:17:21 +08:00 via Android · 2459 次点击
    这是一个创建于 2099 天前的主题,其中的信息可能已经有所发展或是发生改变。
    一直以来都是这么写循环
    for (int i = 0; i < N; i++)

    但是其实 i < N 是结束条件的超集,有时候如果情况比较复杂,准确写出超集似乎给写程序带来不必要的麻烦。

    如果我们这样写
    for (int i = 0; i != N; i++)

    就准确指出了终止条件是当 i == n 时,而且 i 肯定是能到 N 的。但是甚少有人这么写,所以这背后有什么讲究呢。这两种写法各有什么优劣呢。
    25 条回复    2019-03-03 17:52:26 +08:00
    lcorange
        1
    lcorange  
       2019-03-03 11:20:04 +08:00
    比如你循环体内部用了 i 这个变量,如果有人写了错误的代码,修改了 i 的值,比如写了 i++

    这样的话 i 就会在某种异常情况下比 N 大,跳过了 i == N 的情况。循环就停不下来了

    但是写 i < N 可以有避免这种情况发生
    lhx2008
        2
    lhx2008  
    OP
       2019-03-03 11:22:51 +08:00 via Android
    @lcorange 这种情况下,i < N 就不是超集而是准确定义。
    但是我们写 for 循环甚少 N 会变动的情况。那是不是应该不变的时候用 i != N 呢
    lhx2008
        3
    lhx2008  
    OP
       2019-03-03 11:24:42 +08:00 via Android
    @lcorange 楼上第二行我看错了。i 会加 2 这种情况,程序已经不能正常运行了,早抛出错误也好吧?
    geelaw
        4
    geelaw  
       2019-03-03 11:25:26 +08:00 via iPhone   ❤️ 1
    我个人更喜欢 i != N,除非内部对 i 有操作。这是 STL 习惯。
    geelaw
        5
    geelaw  
       2019-03-03 11:27:51 +08:00 via iPhone   ❤️ 2
    实际上那里是循环进行条件,而不是循环结束条件。
    lcorange
        6
    lcorange  
       2019-03-03 11:28:16 +08:00
    @lhx2008 不同代码场景不一致的,比如我有个队列的数据要处理 1~100 号用户的,我写成 i<100,即使内部出错,也能保证部分用户正常使用,程序不会崩溃。但是如果我写成!=100,一旦跳过了 100 号,那服务器只能 500 报错了。

    当然,你说的也没问题。在比如数值计算之类的场景,错误早就发生出现了。也就谈不上避免更大的 bug 了
    lhx2008
        7
    lhx2008  
    OP
       2019-03-03 11:29:15 +08:00 via Android
    @geelaw 是的哈哈,如果看成继续条件写不等于反而是超集。但是我们写代码似乎想的都是终止条件而不是继续条件
    SuperMild
        8
    SuperMild  
       2019-03-03 11:33:55 +08:00   ❤️ 2
    i<100 更节省脑力,不用思考 100 会不会被跳过的问题,而且也更符合逻辑,因为 i != N 的意思是不管大于还是小于 N 只要不等于 N 就应该循环,但事实上的逻辑是只有小于 N 才应该循环,等于及大于 N 都不应该循环。
    hundan
        9
    hundan  
       2019-03-03 11:35:38 +08:00 via Android
    那 i<=N 呢
    SuperMild
        10
    SuperMild  
       2019-03-03 11:37:41 +08:00
    另外,现在很多语言都支持 for in, for range 之类的了,有这个功能的最好尽量使用。
    lhx2008
        11
    lhx2008  
    OP
       2019-03-03 11:47:01 +08:00 via Android
    @SuperMild for range 我觉得是个不太好的发明,就是前后闭合的指定不清晰,python 取消标准 for 循环我觉得是个败笔。至于输入长度,有 ide 都差不多。
    richard1122
        12
    richard1122  
       2019-03-03 13:35:35 +08:00
    用 < 相对于 != 是担心在循环内部有人又修改了 i 的值? 如楼上说的尽量用 for in 甚至是 arr.forEach 这类循环方式,尽量不用可变的循环变量。
    另外同感 for range 不够清晰,kotlin 里面的 0..10 这种也总是记不住到底是多少。。
    Leammin
        13
    Leammin  
       2019-03-03 14:03:15 +08:00 via Android
    《阿里 Java 开发手册》里边也有提到,避免使用等值来作为中断或退出条件,以免条件被"击穿",放在这里应该也是适用的。
    autoxbc
        14
    autoxbc  
       2019-03-03 15:06:20 +08:00 via iPhone
    forEach 更加函数式,只要目标有迭代器,就应该避免用 for
    changnet
        15
    changnet  
       2019-03-03 15:12:57 +08:00 via Android
    尽可能写超集,尤其是这种数字对比,又不增加什么复杂度。比如我们游戏中,策划修改了数值,不写超集程序就容易出问题

    如果你的超集很复杂,这个就得看情况了
    akira
        16
    akira  
       2019-03-03 15:30:48 +08:00
    就准确指出了终止条件是当 i == n 时,而且 i 肯定是能到 N 的。
    -----------------
    这个还真不好说,一旦循环体里面的代码没写好, 跳过了 N, 就死循环了
    whileFalse
        17
    whileFalse  
       2019-03-03 15:34:13 +08:00
    1. 习惯问题
    2. N = -1,step = 2 等条件时,“<”依然适用
    3. 目测大部分人都不 care 这些问题,你爱怎么写就怎么写好了
    ipwx
        18
    ipwx  
       2019-03-03 15:36:31 +08:00
    @lhx2008
    @richard1122 你俩这种说法,说实话就是傲慢。。。一个语言最基本的一个功能,用了这么多次,居然还说“记不住”,其实就是不想记住、看不起这俩语言的设计思路。
    lhx2008
        19
    lhx2008  
    OP
       2019-03-03 15:41:57 +08:00 via Android
    @ipwx 我不知道你如何得出我傲慢,JS 这么多语法糖我不信你记得清楚,比如最简单的 js 里面的 5+种遍历语法和他们的区别。

    关于 range,我知道 python 里面是前闭后开,但是到别的语言里面,变成前闭后闭呢?如果我需求是前闭后闭,是不是还用得后面加一这种难看的写法?

    这些不清晰,不通用的语法糖,在语言设计的时候本来就应该避免,特别是将其作为关键字的时候。
    hhhsuan
        20
    hhhsuan  
       2019-03-03 15:45:11 +08:00 via Android
    超集用在这里合适吗
    richard1122
        21
    richard1122  
       2019-03-03 15:47:43 +08:00
    @ipwx

    不知道你在说啥,1 .. 10 这种只是 kotlin 提供的众多语言特性之下,库函数提供的一个运算符而已,喜欢用的人把它当作一个语法糖也没问题。
    它既不是什么“最基本的功能”,也不是“语言的设计思路”,自己立一个靶子打没意思。
    richard1122
        22
    richard1122  
       2019-03-03 15:49:59 +08:00
    然后才看到楼上提到 python 是左闭右开,而 kotlin 正好相反是左闭又闭的。
    同时它提供了左闭右开的另一个函数 until
    ipwx
        23
    ipwx  
       2019-03-03 16:35:52 +08:00
    @lhx2008 但是对于 Python 而言,range 是 Python 很早就有的基本写法。而且 Python 就一个语法,range,其他都是用户选择的自己的写法。把 Python 的 range 和其他语言比较,然后说 Python 的 range 不清晰,不通用,这就是傲慢。

    因为你在写 Python 不是吗? Python 自己又没有什么一会儿左闭右开,一会儿左开右闭的。所有 Python 的写法,从 range 到 [start: end: step] 这种 slice,都是左闭右开啊。放在一起,它们自己非常融洽,这不就是优雅的语言了吗?
    - - - -

    @richard1122 好吧,我反正不会 Kotlin,你说啥就是什么吧。。。
    ThomasZ
        24
    ThomasZ  
       2019-03-03 16:51:37 +08:00 via Android
    i!=n 这个条件限制范围过于窄,如果你循环体内不慎对 i 进行了自增操作,那么久很有可能跳过 i=n 这个条件导致循环无法终止
    Cbdy
        25
    Cbdy  
       2019-03-03 17:52:26 +08:00 via Android
    第一种主要是 C 风格的,第二种主要是 C++( STL )风格的。这个在 C++ Primer 有介绍
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2881 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 06:45 · PVG 14:45 · LAX 22:45 · JFK 01:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.