C 语言的循环结构(whilefordo-while)是现代命令式编程语言的基石。以 C 语言为基准,可以清晰地看到其他语言在"语法糖"、"安全性"和"迭代器协议"上的演进。

以下是对各语言循环语法的系统总结,重点在于与 C 语言的异同点


基准:C 语言

C语言的循环结构简洁、底层,直接映射到底层汇编的跳转指令。

  • while 循环: 先判断,后执行。
  • do...while 循环: 先执行一次,后判断。
  • for 循环: 最经典的初始化; 条件; 增量结构。

核心特点:

  • 基于索引/指针: C语言的循环通常依赖于整数索引或指针算术来遍历数组。

  • 极度灵活: for 循环的三个部分都可以为空,甚至可以放入多行语句(用逗号连接)。

  • 作用域: 在 C89 标准中,循环变量必须在循环外定义;C99 支持在 for( int i=0; ... ) 内定义,但作用域仅限于循环体。


1、C++ (向后兼容 + 现代 STL)

C++ 完全兼容 C 的三种循环,但在 C++11 及以后标准中引入了基于范围的 for 循环

  • 语法: for (declaration : range) { ... }

  • 与 C 的异同:

    • 相同点: 依然保留 C 风格的 forwhile,用于需要索引或复杂控制的场景。

    • 不同点:

      • 遍历集合更安全: 不需要手动管理索引器,避免了“差一错误”。

      • 支持引用: for (auto& x : vec) 可以直接修改容器元素,C语言则需要解引用指针 (*p)

      • 底层原理: 它是基于迭代器的语法糖,编译器会展开为类似 begin()end() 的调用。


2、Java

Java 在语法上几乎克隆了 C,但增加了增强型 for 循环(也称 for-each)。

  • 经典循环: 与 C 语言完全一致。

  • 增强型 for 循环: for (Type item : collection) { ... }

  • 与 C 的异同:

    • 相同点: while, do-while, 标准 for 逻辑与 C 一致。

    • 不同点:

      • 增强型循环: 类似于 C++,但只能用于数组或实现了 Iterable 接口的对象。

      • 作用域限制:for(int i=0...) 中定义的 i,其作用域严格限制在循环内(C++也是如此,但老 C 代码常不注意)。

      • 无指针算术: Java 没有 C 语言那样的指针算术,所以 for 循环的条件判断通常是 .length.size(),而不是 p != end


3、JavaScript

JS 继承了 C 的语法风格,但由于其动态特性和异步生态,循环变体很多。

  • C 风格: for, while, do-while 语法与 C 完全相同。

  • for...in 遍历对象的可枚举属性(键)。

  • for...of (ES6): 遍历可迭代对象的值。

  • 与 C 的异同:

    • 相同点: 基础 for 循环逻辑一致,常用于遍历数组索引。

    • 不同点:

      • 类型声明是可选的: for (let i=0; ...) 使用 let/var/const 代替 C 的 int

      • 隐式类型转换: JS 的循环条件判断比 C 更“宽”,但也更容易踩坑(如 0 == false)。

      • 遍历方式分离: C 语言只有一种遍历方式(索引/指针);JS 区分了遍历“索引/键”(for-in)和遍历“值”(for-of)。


4、Go (Golang)

Go 语言删除了 C 风格的括号内的三段式 for 循环,并将 whiledo-while 合并进了 for 关键字。

  • 语法: for init; condition; post { ... }

  • 替代 while for condition { ... } (省略 init 和 post)。

  • 替代 do-while Go 没有直接等价物,通常需要配合 for { if !condition { break } }

  • Range 循环: for i, v := range slice { ... }

  • 与 C 的异同:

    • 相同点: 保留了 init; condition; post 的结构,但必须加花括号,且左括号不能换行。

    • 不同点:

      • 语法简化: 只有 for 一个关键字。

      • 多变量赋值: range 可以同时返回索引和值,解决了 C 语言中 iarray[i] 同时书写的繁琐。

      • 逗号 Ok 模式: 遍历 Map 时,可以只取 key 或同时取 key/value。


5、Rust

Rust 借鉴了 Ruby/Python 的迭代器思想,没有 C 风格的 for (i=0; i<n; i++) 循环

  • 无限循环: loop { ... } (比 C 的 while(1) 更清晰,编译器可分析是否返回值)。

  • while 循环: while condition { ... } (类似 C 的 while)。

  • for 循环: 严格基于迭代器。for i in 0..5 { ... }

  • 与 C 的异同:

    • 相同点: 保留了 while 循环。

    • 不同点:

      • 消灭索引循环: Rust 强制使用迭代器。这避免了数组越界(C 语言最常见的 bug 之一)。如果必须用索引,也是用 (0..10).for_each(|i| ...) 这种方式。

      • 所有权机制: 在循环中,变量可能被 move,这是 C 语言没有的概念。

      • break 可以带返回值: let result = loop { break 5; };,这在 C 中需要借助额外变量或函数返回。


6、Python

Python 彻底抛弃了 C 风格的 for (i=0;...)do-while

  • for 循环: 本质是“foreach”。for item in iterable:

  • while 循环: 语法与 C 类似,但去掉了括号。

  • else 分支: Python 循环可以带 else,当循环正常结束(非 break)时执行。

  • 与 C 的异同:

    • 相同点: while 的逻辑流(判断-执行)与 C 一致。

    • 不同点:

      • 强制缩进: 用缩进代替 C 的花括号 {}

      • 没有 do-while 通常用 while True: ... if condition: break 模拟。

      • 没有前置条件的 for C 的 for 可以做任何事(如死循环、复杂初始化);Python 的 for 只能遍历序列。如需计数,必须使用 range() 函数:for i in range(10):


7、Lua

Lua 的循环语法非常独特,它使用 while...endrepeat...until,以及数值型 for 和泛型 for

  • while while condition do ... end

  • repeat (do-while): repeat ... until condition (注意:until 条件为真时结束,C 的 do-while 是条件为假时继续,逻辑是反的)。

  • 数值 for for var = start, end, step do ... end

  • 与 C 的异同:

    • 相同点: 逻辑控制流一致。

    • 不同点:

      • for 循环是数值范围,不是条件判断: C 的 for(i=1; i<=10; i++) 在 Lua 中写作 for i=1, 10, 1 do。Lua 的 for 循环在进入循环前就确定了范围,循环体内修改 i 不会影响循环次数(C 语言中修改 i 会直接影响)。

      • 泛型 for for k, v in pairs(t) do ... end,极其强大的迭代器机制,用于遍历表。


8、PHP

PHP 保留了 C 风格的所有循环,并增加了 foreach。

  • C 风格: for, while, do-while,用法与 C 几乎一模一样。

  • foreach foreach ($arr as$value)foreach ($arr as$key => $value)

  • 与 C 的异同:

    • 相同点: PHP 的 for 循环完全照搬 C,甚至包括在循环体中修改循环变量 $i 的行为。

    • 不同点:

      • 引用传值: foreach ($arr as &$value) 可以直接修改数组元素,这是 C 语言指针操作的高级封装。

      • 数组指针: 虽然有 each()next() 函数(类似 C 的指针移动),但现代 PHP 推荐使用 foreach


9、Zig

Zig 是一门现代系统语言,试图保持 C 的简洁性但增加安全性。它的 for 循环非常强大。

  • while 循环: 类似 C,但支持 continue 时的表达式(如 while (i < 10) : (i += 1))。

  • for 循环: 用于遍历数组、切片、Range。for (items) |item, index| { ... }

  • 与 C 的异同:

    • 相同点: 保留了直接操作内存的能力,写法低层感强。

    • 不同点:

      • 显式捕获: for 循环可以显式捕获 indexitem,甚至用 _ 忽略。

      • 内联汇编感: Zig 的 while 允许在循环标签处定义更新逻辑,这比 C 的 for 末段更灵活。

      • 无隐式转换: 条件判断必须是 bool 类型,C 语言允许 int 直接作为条件(非0即真),Zig 不允许。


现代语言的设计趋势是:让循环表达“意图”而不是“过程”。C 语言表达的是“我初始化一个变量,检查条件,增加变量,然后执行代码”;而现代语言倾向于表达“我要遍历这个集合中的每一个元素”。