xxleyi / learning_list

聚集自己的学习笔记
10 stars 3 forks source link

break continue goto #243

Open xxleyi opened 3 years ago

xxleyi commented 3 years ago

本篇细究编程中的控制流以及一个与禁忌有关的事实:所有类型的控制流最终都由 goto 实现。

随着编程语言的抽象程度越来越高,出现了很多禁忌:永远不要去用XX功能。,比如 eval,比如 goto。

你可能听过,goto 是邪恶的,所有程序员都应该直接将它拉黑。

但禁忌之中,往往藏有不为人知的秘密力量,一旦掌握并驾驭了,我们作为程序员的法力值必定大涨。所谓禁忌,无非是使用难度高,而且容易闯祸罢了。

看这样一个控制流场景该如何实现:n 层循环嵌套,最里层循环想根据某个条件直接跳出所有循环,或者跳到最外层循环重新开始执行。

猛一看,用 break 和 continue 不就解决了?但注意场景是 n 层嵌套,break 和 continue 默认的一层循环。如果是多层的话,就必须借助一个布尔变量,然后在每一层中添加一个判断,从而连续 break 或者连续 continue。

这种情况下,使用 goto 无疑非常简单了:在最外层循环开始和结束的地方设置一个 label,然后在任何一个内层循环里都可以使用 goto label 的方式实现多层 break 或者 continue。

这只是引出 goto 的引子,实际上,理解并认识到所有控制结构都可以归为 goto label 的某种巧妙设计。尤其是,如果能在字节码层面上理解和把握 goto 的话,对控制流的理解必能更上一层楼。

可参见:Jumping Back and Forth · Crafting Interpreters

最后,作为一个小礼物,将一个冷门知识送给你:其实在 JavaScript 中,break 和 continue 后面也是能添加 label 的,借助这个设计,能方便实现多层跳跃。

比如:

let array = [1, 2, 3]
outermost: for (let i of array) {
  console.log('i, ', i)
  for (let j of array) {
    console.log('j, ', j)
    for (let k of array) {
      console.log('k, ' ,k)
      if (k === 2) break outermost
    }
  }
}