是否存在必须使用 while/do-while 而不是 for 的情况?

Posted

技术标签:

【中文标题】是否存在必须使用 while/do-while 而不是 for 的情况?【英文标题】:Are there cases where while/do-while must be used instead of for? 【发布时间】:2013-10-17 04:54:10 【问题描述】:

这是我和老师之间的长期争论。是否存在for循环绝对不能用于代替while/do-while循环的情况?换句话说,是否存在for-loop 无法代替while 循环的特定情况? while/do-whilefor 有什么“不同”吗?

【问题讨论】:

不能吗?我想不出一个。不应该?很多,尤其是在循环开始之前不知道迭代次数的情况 这可能有用:en.wikipedia.org/wiki/For_loop#Equivalence_with_while_loops 我对投票的数量感到惊讶。出于好奇,你站在辩论的哪一边? relevant 循环?你根本不需要任何循环,你只需要if 语句和递归。 【参考方案1】:

不,没有这种情况。每个do-while 循环都可以写成while-循环(通过在循环之前执行一次主体),反之亦然。反过来,每个while-loop

while (X) 
    ...

可以写成

for (; X;) 
    ...

即我们省略了初始化和增量语句。我们还可以通过正确放置初始化和增量从for 转换回while

简而言之,始终可以从一个循环变体转换为其他两个循环变体中的任何一个。 for-loops 只是为您提供了能够限制循环控制变量的范围并在顶部进行任何增量的好处。不用说,在许多情况下,一种特定的循环变体比其他循环变体更有意义。每个都有其特定的用例。

还请注意,乐趣不仅仅以循环结束:还可以将每个循环转换为递归函数,反之亦然(尽管在实践中可能对此有限制;例如,一个运行良好的循环可以,转换为递归函数时,会产生堆栈溢出错误)。


[I]s while/do-whilefor 有任何“不同”吗?

事实并非如此。比如下面两个sn-ps的字节码是一样的:

int x = 0;
while (x < 10) 
    x++;

int x = 0;
for (; x < 10;)   // or: for (; x < 10; x++) 
    x++;

都变成:

   0: iconst_0      
   1: istore_1      
   2: goto          8
   5: iinc          1, 1
   8: iload_1       
   9: bipush        10
  11: if_icmplt     5
  14: return 

cmets 中有关于 for-each 循环的讨论,并且它们可能在本质上与其他循环类型不同。这绝对不是真的; for-each 循环是迭代器周围的纯语法糖(或遍历数组)。每个for-each 循环也可以转换为其他每个循环类型。这是一个例子:

for (String s : l)   // l is a list of strings
    System.out.println(s);

String s;
Iterator<String> iter = l.iterator();  // l is a list of strings
while (iter.hasNext()) 
    s = iter.next();
    System.out.println(s);

都变成:

  24: invokeinterface #33,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
  29: astore_3      
  30: goto          50
  33: aload_3       
  34: invokeinterface #39,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
  39: checkcast     #19                 // class java/lang/String
  42: astore_2      
  43: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
  46: aload_2       
  47: invokevirtual #51                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  50: aload_3       
  51: invokeinterface #57,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
  56: ifne          33

【讨论】:

forwhile 循环只是条件跳转的语法糖! @chrylis 条件语句只是分支的语法糖! @Cruncher 不,分支是我熟悉的每个现实世界架构中的基本操作;它(可选)进行比较,然后用新目标覆盖程序计数器。在 JVM 中,它是 if&lt;cond&gt;,而在 x86 中,它是 J* 操作码。循环被实现为编译器管理的跳转模板。 @user2174407:如果您想向老师证明它们在字节码级别上是等效的,请务必显示此响应。但我想你的老师采取的策略更有可能是:“为了便于阅读,你可以使用while (checkIsTrue) ... ,但不要使用for (; checkIsTrue; ) ... 。” @PeterOlson 我已经描述了如何将 do-while 转换为 while 并且我已经描述了如何将 while 转换为 for。因此,我还描述了如何将 do-while 转换为 for。【参考方案2】:

不,您始终可以将 for 循环重写为 while 循环,而任何 while 看起来都为 for 循环。

<init>
while (condition) 
...
<increment>

相当于:

for (<init>; <condition>; <increment>) 
...

【讨论】:

(对于它的价值,争论似乎是关于你是否总是可以使用 for 循环而不是 while 循环,因此展示如何转换另一种方式可能对OP) @DennisMeng “等价于”在逻辑上是一个双条件 ()。这意味着它是双向的。否则,正确的措辞应该是“暗示”,或者“如果这行得通,那么这也行得通” @Cruncher 我想更好的说法是“交换两者的顺序可以更容易地跟随 OP 与他的老师的辩论”,而不是“展示如何转换.. .对 OP 更有用”。 如果&lt;init&gt; 包含几行代码需要调用函数、声明多个不同的变量或实例化类怎么办?我能想到的唯一限制是您可能无法在 for 循环的 部分中放置任何您想要的东西。 (尽管您可以将该部分放在for 循环之前并在其中省略,但我不知道这是否重要:)) 如果 需要多行,则必须将这些行分组到一个函数中,然后调用该函数。【参考方案3】:

其他答案已经涵盖了 while 循环和 for 循环之间的等价性。也就是说,

while(<expr>) 
  <body>

等价于

for(;<expr>;) 

请注意,可以使用do-while 循环进行类似的缩减。任意do-while循环

do 
  <body>
 while(<expr>);

在功能上等同于

for (boolean firstIter = true; firstIter || <expr>; firstIter = false) 
  <body>

【讨论】:

+1。 除了如果firstIter 已经存在并且在&lt;body&gt; 和/或&lt;expr&gt;使用,则会失败。 回到重点,这是一个不应使用 for 循环的示例。很明显,for 和 while 可以互换,问题是何时使用哪个。【参考方案4】:

“绝对”?我会说不。 然而在 Java 中循环之后的测试(又名 do-while)需要一个相当复杂的“for”条件。这使我们回到布尔绝对值:条件必须评估为真或假。

因此,虽然我无法设想编译器无法被操纵以执行正确逻辑的情况,但我可以在很短的时间内看到任何维护您的程序的人都可能希望您被扔石头(或者可能认为您已经被扔石头了)。

在相关说明中,您可以在 Java 中做任何机器语言无法完成的事情。但是有很多非常好的理由不使用机器语言。当您尝试“可爱”地编写代码时,它们中的大多数同样适用。在您与 0300 的愤怒客户或您的老板或两者通电话之前,一切都是有趣和游戏。

【讨论】:

以上是关于是否存在必须使用 while/do-while 而不是 for 的情况?的主要内容,如果未能解决你的问题,请参考以下文章

C语言学习之循环语句以及breakcontinue语句

C语言学习之循环语句以及breakcontinue语句

for while do-while三种循环体的特点和缺点

04循环结构(while/do-while/for)

三种循环语句的详解和使用(for,while,do-while)

分别使用while、do-while和for语句编程,找出所有的水仙花数并输出。