Go 控制結構

在 Go 中只有很少的幾個控制結構 。這裏沒有 do 或者 while 循環,只有 for。有(靈活的) switch 語句和 if,而 switch 接受像 for 那樣可選的初始化語句。還有叫做類型選擇和多路通訊轉接器的 select。同 C 相比語法有所不同:無需圓括號,而語句體必須總是包含在大括號內。

1、if-else

Go 中的 if 和 C 語言中的 if 很相似,區別主要有三點:

  • 執行體必須要有大括號,且左大括號必須和 if(或 else) 在同一行即使只有一條語句;
  • 條件語句不需要圓括號;
  • 條件語句中可以包含初始化語句,通常用於設置一個(局部)遍量。
if x > 0 { // 左括號必須在同一行
    return y
} else {
    return x
}

if f, err := os.Open(name); err != nil { // 帶初始化語句的條件語句
    return err
}

Go 編譯器關於if-else 的一個 bug

//注意如果在函數中這樣結束,它不會編譯。
if err ! = nil {
    return err
} else {
    return nil
}

2、goto

Go 有 goto 語句 — 明智的使用它。用 goto 跳轉到一定是當前函數內定義的標籤,且標籤是大小寫敏感的。

例如假設這樣一個循環:

func myfunc() {
    i := 0
Here: // 這行的第一個詞,以分號結束作爲標籤
    println(i)
    i++
    goto Here // 跳轉
}

3、for 循環

Go 中沒有 whiledo...while 循環,只有 for循環,可以使用for 實現 while 的功能。

Go 的 for 循環有三種形式,只有其中的一種使用分號。

for init; condition; post { } // 和 C 的 for 一樣
for condition { }             // 和 while 一樣
for { }                       // 死循環, 和 C 的 for(;;) 一樣

例如,使用 for 計算 0~9 的和:

sum := 0
for i := 0; i < 10; i++ {
    sum += i  // sum = sum + i 的簡化寫法
}

**注意:**Go 沒有逗號表達式,而 ++ 和 – 是語句而不是表達式,如果你想在 for 中執行多個變量,應當使用平行賦值,形式爲i, j = ival, jval

// 翻轉數組 a
for i, j := 0, len(a)-1; i < j ; i, j = i+1, j-1 { // 平行賦值
    a[i], a[j] = a[j], a[i] // 這裏也是
}

4、break 和 continue

Go 中的 break 、continue 與 C 語言中的很相似,只是 Go 中的 break 可以添加標籤,表示退出哪一層循環,因此,Go 中的 break 可以退出多層循環,而 C 語言中的 break 只能退出 1層循環。

for i := 0; i < 10; i++ {
    if i > 5 {
        break // 終止這個循環,只打印 0 到 5
    }
    println(i)
}

/* 使用標籤,退出多層循環 */
J: for j := 0; j < 5; j++ {
       for i := 0; i < 10; i++ {
           if i > 5 {
                break J //現在終止的是 j 循環,而不是 i 的那個
           }
           println(i)
       }
    }

5、range

range 可用於循環。它可以對 slice、 array、 string、 map 和 channel 進行循環遍歷。 range 是個迭代器,當被調用的時候,從它循環的內容中返回一個鍵-值對。基於不同的內容, range 返回不同的東西。
當對 slice 或者 array 做循環時, range 返回序號作爲鍵,這個序號對應的內容作爲值。

// 遍歷數組
list := [] string{"a", "b", "c", "d", "e", "f" } 
for k, v := range list { // k-v 鍵值對,k 爲索引(從 0 開始),v 爲對應的值
    // 對 k 和 v 做想做的事情
}

也可以在字符串上直接使用 range。這樣字符串被打散成獨立的 Unicode 字符,並且起始位按照 UTF-8 解析。

for pos, char := range "aΦx" {
    fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
}

// 執行後打印輸出
character 'a' starts at byte position 0
character 'Φ' starts at byte position 1 // Φ佔用兩個字節
character 'x' starts at byte position 3

6、switch

Go 的 switch 非常靈活。表達式不必是常量或整數,執行的過程從上至下,直到找到匹配項,如果沒有匹配項就執行 default 中的語句(如果有 default);而如果 switch 沒有表達式,它會匹配 true 。這產生一種可能 — 使用 switch 編寫 if-else-if-else 判斷序列。

func unhex(c byte) byte {
    switch {
        case '0' <= c && c <= '9':
            return c - '0'
        case 'a' <= c && c <= 'f':
            return c - 'a' + 10
        case 'A' <= c && c <= 'F':
            return c - 'A' + 10
    }
    return 0
}

注意: switch 不會執行完一個 case 後繼續執行下面的 case,但是可以使用關鍵字 fallthrough 使其繼續執行。

switch i {
    case 0: // 空的 case 體
    case 1:
        f() // 當 i == 0 時, f 不會被調用!
}

/* 使用 fallthrough 使執行多個 case */
switch i {
    case 0: // 空的 case 體
    fallthrough
    case 1:
        f() // 當 i == 0 或 1 時,f 被調用!
}

分支可以使用逗號分隔的列表。

func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+': // 相當於 "or"
        return true
    }
    return false
}

7、select

Go 可以通過關鍵字 select 監聽 channel 上的數據流動。

select 默認是阻塞的, 只有當監聽的 channel 中有發送或接收可以進行時纔會運行, 當多個 channel 都準備好的時候, select 是隨機的選擇一個執行的。

在select 裏面可以有 default語法, select 其實就是類似 switch 的功能, default 就是當監聽的channel 都沒有準備好的時候, 默認執行的( select 不再阻塞等待 channel)。

L: for {
    select {
        case <-c:
            i++
            if i > 1 { // 當接收到一個數據時退出循環
                break L
            }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章