Go 入门指南笔记 - 控制结构 - 2

for 结构

  • 如果想要重复执行某些语句,Go 语言中您只有 for 结构可以使用。
  • 一般习惯使用 i、j、z 或 ix 等较短的名称命名计数器。
  • 永远不要在循环体内修改计数器,这在任何语言中都是非常差的实践!
  • 得益于 Go 语言具有的平行赋值的特性,还可以在循环中同时使用多个计数器 for i, j := 0, N; i < j; i, j = i+1, j-1 {}
package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Printf("This is the %d iteration\n", i)
    }
}

for 结构的第二种形式是没有头部的条件判断迭代(类似其它语言中的 while 循环),基本形式为:for 条件语句 {}。但这是不好的实践。

package main

import "fmt"

func main() {
    var i int = 5

    for i >= 0 {
        i = i - 1
        fmt.Printf("The variable i is now: %d\n", i)
    }
}

无限循环

  • 最后一个形式也可以被改写为 for true { },但一般情况下都会直接写 for { }
  • 如果 for 循环的头部没有条件语句,那么就会认为条件永远为 true,因此循环体内必须有相关的条件判断以确保会在某个时刻退出循环。
  • 想要直接退出循环体,可以使用 break 语句或 return 语句直接返回
  • break 只是退出当前的循环体,而 return 语句提前对函数进行返回,不会执行后续的代码。
  • 无限循环的经典应用是服务器,用于不断等待和接受新的请求。
for t, err = p.Token(); err == nil; t, err = p.Token() {
    // ...
}

for-range

  • 它可以迭代任何一个集合
  • 一般形式为:for ix, val := range coll { }
  • val 始终为集合中对应索引的值拷贝,因此它一般只具有只读性质,对它所做的任何修改都不会影响到集合中原有的值
  • 如果 val 为指针,则会产生指针的拷贝,依旧可以修改集合中的原值
  • 一个字符串是 Unicode 编码的字符(或称之为 rune)集合,因此您也可以用它迭代字符串
  • 每个 rune 字符和索引在 for-range 循环中是一一对应的。它能够自动根据 UTF-8 规则识别 Unicode 编码的字符。
for pos, char := range str {
// ...
}
for i, j, s := 0, 5, "a"; i < 3 && j < 100 && s != "aaaaa"; i, j,
    s = i+1, j+1, s + "a" {
    fmt.Println("Value of i, j, s:", i, j, s)
}

Break 与 continue

break

  • 一个 break 的作用范围为该语句出现后的最内部的结构,它可以被用于任何形式的 for 循环(计数器、条件判断等)。
  • 在 switch 或 select 语句中,break 语句的作用结果是跳过整个代码块,执行后续的代码。
package main

func main() {
    for i:=0; i<3; i++ {
        for j:=0; j<10; j++ {
            if j>5 {
                break // break 只会退出最内层的循环
            }
            print(j)
        }
        print("  ")
    }
}

continue

  • 关键字 continue 忽略剩余的循环体而直接进入下一次循环的过程,但不是无条件执行下一次循环,执行之前依旧需要满足循环的判断条件。
  • 只能被用于 for 循环中。
package main

func main() {
    for i := 0; i < 10; i++ {
        if i == 5 {
            continue
        }
        print(i)
        print(" ")
    }
}

标签与 goto

  • for、switch 或 select 语句都可以配合标签(label)形式的标识符使用,即某一行第一个以冒号(:)结尾的单词
  • 标签的名称是大小写敏感的,为了提升可读性,一般建议使用全部大写字母
package main

import "fmt"

func main() {

LABEL1:
    for i := 0; i <= 5; i++ {
        for j := 0; j <= 5; j++ {
            if j == 4 {
                continue LABEL1
            }
            fmt.Printf("i is: %d, and j is: %d\n", i, j)
        }
    }

}
  1. continue 语句指向 LABEL1,当执行到该语句的时候,就会跳转到 LABEL1 标签的位置。
  2. 当 j==4 和 j==5 的时候,没有任何输出
  3. 标签的作用对象为外部循环,因此 i 会直接变成下一个循环的值,而此时 j 的值就被重设为 0,即它的初始值。
  4. 如果将 continue 改为 break,则不会只退出内层循环,而是直接退出外层循环了。

还可以使用 goto 语句和标签配合使用来模拟循环。

package main

func main() {
    i:=0
    HERE:
        print(i)
        i++
        if i==5 {
            return
        }
        goto HERE
}

使用标签和 goto 语句是不被鼓励的:它们会很快导致非常糟糕的程序设计,而且总有更加可读的替代方案来实现相同的需求。

如果您必须使用 goto,应当只使用正序的标签(标签位于 goto 语句之后),但注意标签和 goto 语句之间不能出现定义新变量的语句,否则会导致编译失败。

如果觉得我的文章对您有用,请在支付宝公益平台找个项目捐点钱。 @Victor Mar 9, 2019

奉献爱心