if 分支结构

  1. 关键字 if 是用于验证布尔型的语句,如果该条件成立,则会执行 if 后由大括号{}括起来的代码块,否则就忽略该代码块继续执行后续的代码。
  2. 如果存在第二个分支,则可以在上面代码的基础上添加 else 关键字以及另一代码块。
  3. 如果存在第三个分支,则可以在上面代码的基础上添加 else if 关键字以及另一代码块。
  4. 分之数量是没有限制的,但是为了代码的可读性,还是不要在 if 后面加入太多的 else if 结构,如果必须使用这种形式,则尽可能把先满足的条件放在前面。
  5. 关键字 if 和 else 之后的左大括号{必须和关键字在同一行,。

    1. var ten int = 11
    2. if ten > 10 {
    3. fmt.Println(">10")
    4. } else {
    5. fmt.Println("<=10")
    6. }

    特殊写法
  6. 可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断。

  7. 这种写法可以将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在 if、else 语句组合中。
    1. if err := Connect(); err != nil {
    2. fmt.Println(err)
    3. return err
    4. }

for 循环结构

  1. go 是一门简洁的语言,设计时只有for一个循环语句关键字,但支持3种形式。没有 while 和 do-while 结构。
  2. for 后面的条件表达式不需要用圆括号()括起来。左大括号 { 必须和关键字在同一行
  3. for 包含初始化语句、条件表达式、结束语句,这 3 个部分均可缺省:
    1. 初始化语句:与C语言一样,都允许在循环条件中定义和初始化变量,但是Go语言不支持以逗号为间隔的多个赋值语句,如果变量在此处被声明,其作用域将被局限在这个 for 的范围内。
    2. 条件表达式:条件语句每次循环都会重新检查,因此不建议在条件语句中使用函数,应提前计算好条件并以变量或常量代替。忽略条件表达式后默认形成无限循环。
    3. 结束语句:结束每次循环前执行的语句,如果循环被 break、goto、return、panic 等语句强制退出,结束语句不会执行。

for

for 普通循环

  1. for i:= 0; i < 10; i++ {
  2. fmt.Println(i)
  3. }

for 实现 while

  1. sum:= 0
  2. for sum < 1000 {
  3. sum +=sum
  4. }
  5. fmt.Print(sum)

for 实现 do while

考虑到无限循环的场景,让开发者不用写无聊的 for(;;){}do{} while(1);,而直接简化为如下的写法:

  1. run := 0
  2. b := false
  3. for {
  4. b = true
  5. if b {
  6. break
  7. }
  8. run++
  9. if run >= 5 {
  10. return errors.New("文件名无法构造")
  11. }
  12. }

for range

  1. for range 结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用。
  2. for range 可以遍历数组、切片、字符串、map 及通道(channel),for range 语法上类似于其它语言中的 foreach 语句。
  3. 在需要时,可以使用匿名变量对 for range 的变量进行选取。
  4. val 始终为集合中对应索引的值拷贝,因此它一般只具有只读性质,对它所做修改都不会影响到集合中原有值。
  5. 因为迭代返回的变量是一个在迭代过程中根据切片依次赋值的新变量,所以 val 的地址总是相同的。
    1. for key, val := range coll {
    2. ...
    3. }

    通过 for range 遍历的返回值有一定的规律:

    • array (数组)、slice (切片)、string (字符串)—— 返回索引和值。
    • map (集合) 返回键和值。
    • channel(通道)只返回通道内的值。

range array、slice
  1. // key 和 value 分别代表切片的下标及下标对应的值
  2. for key, value := range []int{1, 2, 3, 4} {
  3. fmt.Printf("key:%d value:%d\n", key, value)
  4. }
  5. key:0 value:1
  6. key:1 value:2
  7. key:2 value:3
  8. key:3 value:4

range string
  1. // key 和 value 分别代表字符串的索引和字符串中的每一个字符(实际类型是 rune 类型)
  2. var str = "hello 你好"
  3. for key, value := range str {
  4. fmt.Printf("key:%d value:0x%x\n", key, value)
  5. }
  6. key:0 value:0x68
  7. key:1 value:0x65
  8. key:2 value:0x6c
  9. key:3 value:0x6c
  10. key:4 value:0x6f
  11. key:5 value:0x20
  12. key:6 value:0x4f60
  13. key:9 value:0x597d

range map

map 遍历时,遍历输出的键值是无序的,如果需要有序的键值对输出,需要对结果进行排序。

  1. // key 和 value 分别代表 map 的索引键 key 和索引对应的值,一般被称为 map 的键值对
  2. m := map[string]int{
  3. "hello": 100,
  4. "world": 200,
  5. }
  6. for key, value := range m {
  7. fmt.Println(key, value)
  8. }
  9. hello 100
  10. world 200

range channel

for range 可以遍历通道(channel),接收通道数据。但是通道在遍历时,只输出一个值,即管道内的类型对应的数据。

  1. c := make(chan int)
  2. go func() {
  3. c <- 1
  4. c <- 2
  5. c <- 3
  6. close(c)
  7. }()
  8. for v := range c {
  9. fmt.Println(v)
  10. }

选择希望获得的变量

使用 for range 循环遍历某个对象时,一般不会同时需要 key 或者 value,这个时候可以使用匿名变量来完成。

  1. m := map[string]int{
  2. "hello": 100,
  3. "world": 200,
  4. }
  5. for _, value := range m {
  6. fmt.Println(value)
  7. }
  8. 100
  9. 200

switch

  1. switch可以使用任何类型或者表达式作为条件语句。
  2. case 按照从上到下的顺序进行求值,直到找到匹配的项,默认带break不需要写,一旦条件符合自动终止。如希望继续执行下一个case,需要使用fallthrough语句(不推荐使用)。无法匹配可以使用default分支,每个switch只能有一个分支。
    普通使用
    1. var a = "hello"
    2. switch a {
    3. case "hello":
    4. fmt.Println(1)
    5. case "world":
    6. fmt.Println(2)
    7. default:
    8. fmt.Println(0)
    9. }
    一分支多值
    1. var a = "mum"
    2. switch a {
    3. case "mum", "daddy":
    4. fmt.Println("family")
    5. }
    分支表达式
    这种情况的 switch 后面不再需要跟判断变量,可理解为 switch true
    1. var a = 11
    2. switch {
    3. case a > 10 && a < 20:
    4. fmt.Println("case 1")
    5. //继续执行下一个case
    6. fallthrough
    7. case a >=1:
    8. fmt.Println("case 2")
    9. }
    10. // log
    11. case 1
    12. case 2

goto

goto 语句通过标签进行代码间的无条件跳转,同时 goto 语句在快速跳出循环、避免重复退出上也有一定的帮助,使用 goto 语句能简化一些代码的实现过程。但该语句容易引起逻辑混乱,需谨慎使用。

  1. func main() {
  2. for x := 0; x < 10; x++ {
  3. for y := 0; y < 10; y++ {
  4. if y == 2 {
  5. // 跳转到标签
  6. goto breakHere
  7. }
  8. }
  9. }
  10. // 手动返回, 避免执行进入标签
  11. return
  12. // 标签
  13. breakHere:
  14. fmt.Println("done")
  15. }
  1. err := firstCheckError()
  2. if err != nil {
  3. goto onExit
  4. }
  5. err = secondCheckError()
  6. if err != nil {
  7. goto onExit
  8. }
  9. fmt.Println("done")
  10. return
  11. onExit:
  12. fmt.Println(err)
  13. exitProcess()

break、continue

  1. break 语句可以结束 for、switch 和 select 的代码块,另外 break 语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的 for、switch 和 select 的代码块上。
  2. continue 语句可以结束当前循环,开始下一次的循环迭代过程,仅限在 for 循环内使用,在 continue 语句后添加标签时,表示开始标签对应的循环。 ```go JLoop: for j := 0; j < 5; j++ {
    1. for i := 0; i < 10; i++ {
    2. if i > 5 {
    3. break JLoop
    4. }
    5. if i == 1 {
    6. continue
    7. }
    8. fmt.Println(i)
    9. }
    } fmt.Println(“end”) }

// log 0 2 3 4 5 end

  1. ```go
  2. func main() {
  3. OuterLoop:
  4. for i := 0; i < 2; i++ {
  5. for j := 0; j < 5; j++ {
  6. switch j {
  7. case 2:
  8. fmt.Println(i, j)
  9. continue OuterLoop
  10. }
  11. }
  12. }
  13. }
  14. // log
  15. 0 2
  16. 1 2