Golang 學習筆記:流程控制

條件語句

Go語言沒有do-while語句,而for語句擁有更普遍的含義和用途switch語句也有進一步的擴展,支持類型判斷和初始化子句等。編程

常見的流程控制的關鍵字有:數組

  • defer:用於捕獲異常和資源回收等工做
  • select:用於多支選擇(配合通道使用)
  • go:用於異步啓動 goroutine 並執行特定函數
  • if判斷語句
func main() {
    a := 15
    if a < 20 {
        fmt.Println("a小於20")
    }
    //順序執行
    fmt.Println("a的值是", a)
}

if判斷語句是最簡單的判斷,缺點在於沒法返回false的狀況,爲了增長這一功能就要用到if-else語句。併發

  • if-else語句
func main() {
    a := 20
    if a < 20 {
        fmt.Println("a小於20")
    } else {
        fmt.Println("a大於等於20")
    }
}

若是想判斷a值是否大於10同時小於20時,if-else語句就不可以知足需求了。避免使用嵌套if-else語句,由於實現邏輯複雜,使得代碼可讀性較差。接下來要提到到的else-if語句能夠很好的解決這個問題。異步

  • else-if語句
//判斷a值是否在區間(10,20)
func main() {
    a := 15
    if a > 20 {
        fmt.Println("a大於20")
    } else if a < 10 {
        fmt.Println("a小於10")
    } else {
        fmt.Println("a小於20")
        fmt.Println("a大於10")
    }
    fmt.Println("a的值爲:", a)
}
/*
a小於20
a大於10
a的值爲: 15
*/

else-if語句可使用多個else-if關鍵字函數

func main() {
    a := 13
    if a > 20 {
        fmt.Println("a大於20")
    } else if a < 10 { //else-if語句後
        fmt.Println("a小於10")
    } else if a == 15 {
        fmt.Println("a等於15")
    } else {
        fmt.Println("a小於20")
        fmt.Println("a大於10")
        fmt.Println("a不等於15")
    }
    fmt.Println("a的值爲:", a)
}
/*
a小於20
a大於10
a不等於15
a的值爲: 13
*/

選擇語句

switch語句

switch表示選擇語句的關鍵字,根據初始化表達式得出一個值,而後根據case語句的條件,執行相應的代碼塊,最終返回特定內容。
若是沒有遇到特定的case,則可使用default case;若是已經遇到符合條件的case,那麼後面的case都不會被執行。
在Go語言中,switch有兩種類型學習

  • 表達式switch:case包含與switch表達式的值進行比較的表達式
  • 類型switch:case包含於特殊註釋的switch表達式的類型進行比較的類型

表達式switch

func main() {
    score := 90
    level := "C"

    switch score { //對應表達式的值選擇case
    case 90:
        level = "A"
    case 80:
        level = "B"
    case 70:
        level = "C"
    case 60:
        level = "D"
    default:
        level = "NULL"
    }
    fmt.Printf("你的等級是%s\n", level)
}

這種語句寫法雖然簡單,可是缺點也很明顯,緣由是它直能判斷單值的case,對於除了固定的case之外的值,全都被返回到了default,使得輸出數據變得不合理。例如,socre值爲91,卻打印出「你的等級是NULL」。code

爲了解決這一問題,咱們可使用完整的switch表達式,同時容許多個switch語句相互關聯,好比下面的代碼塊,容許第二個switch語句接收第一個switch語句返回值做爲選擇條件。索引

func main() {
    score := 90
    level := "C"
    switch score { //判斷成績所屬區間
    case 90:
        level = "A"
    case 80:
        level = "B"
    default:
        level = "NULL"
    }

    switch { //能夠接受上一個switch語句的case值,switch語句後的條件表達式不限制爲常量或表達式,容許什麼都不寫
    case level == "A":
        fmt.Println("優秀") //單個case能夠多個結果選項
        fmt.Println("Good!")

    case level == "B":
        fmt.Println("良好")

    default:
        fmt.Println("你的成績不存在!")
    }
    fmt.Println("你的成績是:", score)
}
/*
優秀
Good!
你的成績是: 90
 */

咱們能夠總結出Go語言的switch語句有如下特色:接口

  • switch後面的條件表達式能夠爲空、常量、整數
  • case表達式能夠有多個
  • 左花括號必須同switch一行
  • 無需像C語言同樣使用break關鍵字結束case(待補充)
  • 單個case值能夠出現多個選擇結果
  • 多個switch語句之間能夠相互關聯(容許接收前一個switch語句的返回結果)
  • fallthrough關鍵字能夠把當前case控制權交給下一個case語句執行(無論什麼條件都會被強制執行)
/*fallthrough寫法*/
func main() {
    score := 80 
    level := "B"
    switch score { //對應表達式的值選擇case
    case 90:
        level = "A"
    case 80:
        level = "B"
        fallthrough //把當前case控制權交給下一個語句判斷,當前case語句被忽略
    default:
        level = "NULL"
    }
    fmt.Printf("你的等級是%s\n", level)
}
/*
你的等級是NULL
*/

以上語句score等於80,正常來看會選擇對應case值80的選擇語句,可是fallthrough關鍵字會忽略本層case語句的選擇條件,強制執行下一個case語句的內容(無論什麼條件都會被執行),因此輸出的內容是default的選擇語句。資源

type-switch語句

類型switch語句能夠根據條件表達式的類型自動選擇執行哪一個case代碼塊。使用類型switch語句時,須要判斷的變量必須是接口類型的變量。有關接口的知識點將在之後的學習補充和完善。
注意:type-switch語句不容許使用fallthrough

type Element interface{} //聲明接口類型

func main() {
    var e Element = "這是一個字符串"
    switch value := e.(type) { //根據類型選擇對應case語句
    case int:
        fmt.Println("int", value)
    case string:
        fmt.Println("string", value)
    default:
        fmt.Println("unknown", value)
    }
}
/*
string 這是一個字符串
*/

初始化switch

一樣的,switch語句後面也能夠寫上初始化表達式,而且只能有一句語句

(待補充)

select語句

在選擇語句中,除了switch語句,還有另外一種select語句,這種語句用於配合通道(channel)的讀寫操做,用於多個channel的併發讀寫特性。有關併發的特性將在後面的學習中介紹。**switch語句是按順序從上到下依次執行的,select語句是隨機判斷一個case來判斷,直到匹配其中的一個case爲止。

package main

import (
    "fmt"
)

//併發編程的內容
func main() {
    a := make(chan int, 1024)
    b := make(chan int, 1024)

    for i := 0; i < 10; i++ {
        fmt.Printf("第%d次", i)
        a <- 1 //
        b <- 1

        select {
        case <-a:
            fmt.Println("from a")
        case <-b:
            fmt.Println("from b")
        }
    }
}

循環語句

在Go語言中,循環語句的關鍵字是for,沒有while關鍵字。for語句能夠根據指定的條件重複執行其內部的代碼塊,這個判斷條件通常是由for後面的子語句給出的。

for的子語句

for語句後面的三個子語句咱們稱爲:初始化子語句條件子語句後置子語句,這三個子語句順序不能顛倒,其中條件子語句是必需的,條件子語句會返回一個布爾型,true執行代碼塊,false則跳出循環。

func main() {
    a := 0
    b := 5
    for a < b { //只有條件子語句,實際是 for ; a<b ; 的簡寫 
        a++
        fmt.Println("a的值是:%d", a)
    }
}
/*
a的值是:%d 1
a的值是:%d 2
a的值是:%d 3
a的值是:%d 4
a的值是:%d 5
*/

range子語句

每個for語句均可以使用一個特殊的range子語句,其做用相似迭代器,用於輪詢數組或者切片值的每個元素,也能夠用於輪詢字符串的每個字符串和字典值中的鍵值對,甚至還能夠持續讀取一個通道類型值中的元素

注意:range關鍵字左邊表示是一對索引-值對

package main

import (
    "fmt"
)

func main() {
    str := "asdf"
    for i, char := range str { //range關鍵字右邊是range表達式,表達式通常寫在for語句前面,提升代碼可讀性
        fmt.Printf("這是第%d個字符串的值是:%d\n", i, char)
    }
    for _, char := range str {
        fmt.Println(char) //使用空標識符_屏蔽索引值,只打印字符值
    }
    for i := range str {
        fmt.Println(i) //使用空標識符_屏蔽字符值,只打印索引值
    }
    for range str {
        fmt.Println("輪詢完畢")
    }
}

/*
這是第0個字符串的值是:97
這是第1個字符串的值是:115
這是第2個字符串的值是:100
這是第3個字符串的值是:102
97
115
100
102
0
1
2
3
輪詢完畢
輪詢完畢
輪詢完畢
輪詢完畢
*/

對於空字典或切片、空數組、空字符串等狀況,for語句會直接結束,不會循環。

func main() {
    str := "" //空字符串
    for i, char := range str { //只有條件子語句
        fmt.Printf("這是第%d個字符串的值是:%d\n", i, char)
    }
    for _, char := range str {
        fmt.Println(char) //值對
    }
    for i := range str {
        fmt.Println(i) //索引
    }
    for range str {
        fmt.Println("輪詢完畢")
    }
    fmt.Println("這是一個空字符串") //字符串爲空,跳出for循環
}

/*
這是一個空字符串
*/

延遲語句

在Go語言中,除了上述提到的常規流程控制的語句以外,還有一些特殊的控制語句,也是Go語言的語法特性之一。defer語句就是其中一個,用於延遲調用指定函數,defer關鍵字只能出如今函數內部,而且只能用於調用外部函數。例如,以下的代碼塊,defer就是 fmt.Println 外部函數的延遲調用,被延遲的操做是defer後面的語句。

func main() {
    defer fmt.Println("請延遲執行這條語句") //defer關鍵字只能出現於函數內部,而且用於外部函數的調用
    fmt.Println("請先執行這條語句")
}

/*
請先執行這條語句
請延遲執行這條語句
*/

defer 有兩大特色:

  • 只有當defer語句所有執行完畢時,defer所在函數纔算真正結束執行
  • 當函數中有defer語句時,須要等待全部defer語句執行完畢,纔會執行return語句。

    /*利用defer特性打印反向數字列表*/
    var i int = 0
    func print(i int) { //構造打印函數
        fmt.Println(i)
    }
    func main() {
        for ; i < 5; i++ { //省略初始化子語句
            defer print(i) //因爲defer的延遲特性,知足先進後出,因此可將defer當作一個棧,依次打印出棧順序
        }
    }
    
    /*
    4
    3
    2
    1
    0
    */

    標籤

    在Go語言中,還有一個特殊的概念那就是標籤(相似彙編語言),能夠給for、switch、select語句等流程控制代碼塊打上一個標籤,配合標籤標識符能夠方便跳轉到某一個地方繼續執行,有助於提升編程效率。

    func main() {
    LOOP1: //標籤
        for i := 0; i < 5; i++ {
            switch {
            case i < 5:
              fmt.Println("A")
                break LOOP1 //跳到標籤LOOP1,處於for循環之外,再也不執行任務
          case i == 5:
                fmt.Println("B")
          }
            fmt.Println("i的值是:", i) //因爲使用break跳轉到標籤LOOP1,此條語句再也不執行
      }
    }

A
*/

爲了提升代碼的可讀性,建議標籤名稱使用大寫字母和數字。標籤能夠標記任何語句,並不限定於流程控制語句,**未使用的標籤會引起錯誤**。

### break語句

break語句用於打斷當前流程控制,例如:

package main

import (

"fmt"

)

func main() {

for i := 0; i < 10; i++ {
      fmt.Println("i的值是:", i)
      if i > 4 {
          break //打斷,跳出當前for循環
      }
  }

}

/*
i的值是: 0
i的值是: 1
i的值是: 2
i的值是: 3
i的值是: 4
i的值是: 5
*/

對於嵌套流程控制語句,break只能中斷當前循環,不能跳出外層循環。

package main

import (

"fmt"

)

func main() {

for i := 0; i < 5; i++ {
      switch {
      case i < 5:
          fmt.Println("A")
          break //跳出當前switch循環,未跳出外層for循環
      case i == 5:
          fmt.Println("B")
      }
      fmt.Println("i的值是:", i)
  }

}

/*
A
i的值是: 0
A
i的值是: 1
A
i的值是: 2
A
i的值是: 3
A
i的值是: 4
*/

### continue語句

與break語句相反,continue語句則用於跳轉到指定代碼塊或標籤位置**繼續執行任務,且只能用於for循環**。

func main() {
LOOP1: //標籤

for i := 0; i < 5; i++ {
      switch {
      case i < 5:
          fmt.Println("A")
          continue LOOP1 //跳到標籤LOOP1,處於for循環之外,繼續執行任務
      case i == 5:
          fmt.Println("B")
      }
      fmt.Println("i的值是:", i) /
  }

}

/*
A
A
A
A
A
*/

### goto語句

goto語句用於**無條件跳轉到相同函數的帶標籤語句,且只能在同一函數跳轉**。

func main() {

for i := 0; i < 3; i++ {

      fmt.Println("A")
      goto LOOP2       //跳到標籤LOOP2
      fmt.Println("B") //忽略不執行
  LOOP2:
      fmt.Println("i的值是:", i) //順序執行
  }

}

/* A i的值是: 0 A i的值是: 1 A i的值是: 2 */

相關文章
相關標籤/搜索