Skip to content

语句: 控制程序的流程

目前主流的编程语言中都包含 if while for 这样的流程控制语句,这在最初的编程语言中是不存在的。直到 20 世纪 60 年代后期,提倡让读写程序更加轻松的时代潮流中,结构化程序设计应运而生。其中的集大成者就是 C 语言,这才让 if while for 这样的语句习以为常。

if 语句

if 语句用于判断,理论上任何程序设计语言都必须必须包含判断语句,尽管它可能不是以 if 的形式出现,例如汇编语言就没有 if 语句,但是不意味着它不存在判断:

C
int main(){
  int x = 123;
  /* if 语句前 */
  if(x == 456){
    /* if 语句中 */
  }
  /* if 语句后 */
}

上面的语句编译为汇编之后:

Elixir
_main:
      ...
      movl    $123, -8(%rbp)   # 将 123 存入寄存器 x = 123
      # if 语句前
      movl    -8(%rbp), %eax   # 将寄存器中的值转移到临时寄存器中
      cmpl    $456, %eax       # 比较 456 和寄存器中的值
      jne     LBB1_2           # 如果不相等就跳转到 LBB1_2 处
      # if 语句中  如果 cmpl 相等执行它,不等不执行它
LBB1_2:
      # if 语句后  如果 cmpl 不想等执行它
      ...

因此严格意义上汇编不是没有 if 语句,而是通过 cmpl 和 jne 指令替代了。一个具有图灵完整的编程语言一定是包含判断的。

它实际上是类似中断的概念,即一个寄存器中如果大于 0 就跳转这样的逻辑

else

有 if 就一定伴随着 else。if 判断有两个结果,else 就是提供了一种分支来对两个不同的结果提供功能。

goto 语句

goto 语句是一个饱受诟病但是异常强大的语句,它借鉴了汇编语言的标签语法来实现对流程的直接跳转,由于他过于灵活在现代主流的编程语言中要么不在提供该语句要么对他进行了限制。

汇编中的流程控制完全依赖于 goto 语句,同样在 C 语言中能够使用 goto 来模拟流程控制语句。实际上 if .. else、while、break 等这些语法结构都是为了限制 goto 的灵活性而创建的语句

while 语句

while 语句能够让反复执行的 if 语句更加简洁,尽管它并不是必须的(C 语言中):

C
void use_while(int x){
  print("use_while");
  while(x > 0){
    print("%d", x);
    x--;
  }
}

void no_use_while(int x){
  print("not_use_while");
 START_LOOP:
  if(!(x > 0)) goto END_LOOP;
  x--;
  goto START_LOOP;
 END_LOOP:
  return;
}

配合 while 还存在一个跳出 while 的 break 语句,它的效果等价于 goto END_LOOP。还有一个 continue 同样能够用 goto 来实现:

C
// 遇到 continue 逻辑
goto CONTINUE_LOOP;

CONTINUE_LOOP:
  // expression
  goto START_LOOP

for 语句

理论上有了 while 语句,for 并不是必须的。for 只是让执行特定次数的 while 语句更加简洁而存在的:

C
for(i = 0; i < N; i++){
  printf("%d\n", i)'
}

// 使用 while 改写
i = 0;
while(i < N){
  printf("%d\n", i);
  i++;
}

他将三处散落在代码外部的组件整合到 for 语句中:

for loop

foreach: 迭代器

现在面向对象的发展,提出了迭代器概念。这就扩展了 for 语句允许它直接循环迭代器中的元素。甚至像 Python 语言中的 for 直接就是 foreach 模型,它尽管脱胎于 C 但是并没有提供等价于 C 语言中 for 语句的语句。

而 java 比较特殊它通过特殊的扩展语法来实现 for 的常规语法解释和 foreach 模型:

Java
int[] items = new int[]{1, 2, 3, 4, 5};

// 一般 for 语句
for(int i = 0; i < items.length; i++){
  int item = items[i];
  System.out.println(item);
}

// foreach 模型扩展
for(int item: items){
  System.out.println(item);
}