写在前面

* Go语言的逻辑流程语法很简洁
* 这里指的逻辑流程语法也就是标题中的“循环,判断,分支,延长”,当然这不是一种严格的说法
* 就拿循环语句为例,Go语言就一个for语句,真是治愈了强迫症

Go语言循环语句for

* Go语言的for,和其他流行的编程语言大体相同,但是更简单一些
* for语句分为4个部分(笔者自己划分,官方文档说的是3部分):
    * 初始语句:在第一次迭代前初始化一些变量,而这些变量只能for语句的循环体中使用,可省略
    * 判断语句:在每次迭代前,判断循环终止的条件,如果省略,将进入无限循环
    * post语句(这个不好翻译): 在每次迭代结束时运行,可以省略
    * 循环体(笔者自己加入):这一部分就是每次迭代要做的事情,用大括号{}来规定访问范围
* 特别地,Go语言的for语句中,初始语句,判断语句,post语句不需要括号包围,而每个语句之间都用符号;隔开
```golang
//基本形式
for i := 1;  i <= 10; i++ {
    i += 1
}

//省略了初始语句和post语句
sum := 1
for ; sum < 1000; {
    sum += sum
}

```
* for 语句的while形式
```golang
sum := 1
for sum<1000 {
    sum += sum
}
```
* for语句的无限循环
```golang
for {
}
```

Go语言中的判断语句if

* Go语言中的if语句,同样地,省略符号(),用大括号{}来定义判断成功要执行的内容
```golang
if i < 10 {
    fmt.Println(i)
}
```
* 另外,在if语句的判断中还能添加一条语句(short statement),其中定义的变量只能在if语句的执行部分进行调用
```golang
//先执行short statement,再执行判断
if v := math.Pow(x, n); v < lim {
    return v
}
return lim
}

```
* if-else语句,这里采用官方教程的代码,因为发现了点有趣的现象
```golang
package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // can't use v here, though
    return lim
}
//注意到,Println函数中的逗号,并没有错误,少了反而会报错
func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}
//输出的结果是这样的:
27 >= 20
9 20

Program exited.
```
* 上面的程序,按一般的思维,程序从左到右,从上到下运行,而这里的输出结果不应该先输出9,27 >= 20,20吗?为此再添加多个值
```golang
package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // can't use v here, though
    return lim
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
        pow(3, 4, 20),
        pow(3, 5, 10),
    )
}
//输出的结果是这样的:
27 >= 20
81 >= 20
243 >= 10
9 20 20 10

Program exited.
```
* 由此可以初步判断println先执行每个pow函数中的语句,而每个pow函数的放回值则最后执行,同样是按顺序

Go语言中的分支语句switch-case

* Go中的switch-case,也是不用括号()的,但需要大括号{}
* 不需要担心是否漏写了break,因为每个分支执行完并不会继续执行下一个分支的语句
* 支持“变量分支”,会更加灵活   
```golang
package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    test := runtime.GOOS
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case test:
        fmt.Println("Linux.")
    default:
        fmt.Printf("%s.\n", os)
    }
}
```
* 还能省略switch的状态,这个时候,将对每个case进行顺序判断(判断true or false),哪个case为真执行哪个,因此可以把上面的代码改写为:
```golang
package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("When's Saturday?")
    today := time.Now().Weekday()
    switch  {
    case time.Saturday == today + 0:
        fmt.Println("Today.")
    case time.Saturday == today + 1:
        fmt.Println("Tomorrow.")
    case time.Saturday == today + 2:
        fmt.Println("In two days.")
    default:
        fmt.Println("Too far away.")
    }
}

```
* 还需要注意的是,省略了switch的状态后,执行的将是第一次判断正确的case语句的内容

Go语言中的延迟语句defer

* defer语句,它的作用是延迟进行某些操作
* 在某个函数A中可以使用defer来使其中调用的函数B延迟运行,将使得函数B能在函数A返回时再运行
```golang
package main

import "fmt"

func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}
//输出结果是
hello
world

Program exited.
```
* 实际上,这是用了栈(后进先出LIFO)
```golang
package main

import "fmt"

func main() {
    fmt.Println("counting")

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

    fmt.Println("done")
}
//输出
counting
done
9
8
7
6
5
4
3
2
1
0
```
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄