Go 語言編程 — 邏輯控制語句

目錄

條件判斷

在這裏插入圖片描述

if/else 語句

在這裏插入圖片描述
示例:

package main

import "fmt"

func main() {
   /* 局部變量定義 */
   var a int = 100;
 
   /* 判斷布爾表達式 */
   if a < 20 {
       /* 如果條件爲 true 則執行以下語句 */
       fmt.Printf("a 小於 20\n" );
   } else {
       /* 如果條件爲 false 則執行以下語句 */
       fmt.Printf("a 不小於 20\n" );
   }
   fmt.Printf("a 的值爲 : %d\n", a);

}

可見,Golang 中的條件表達式不需要使用 “()” 括起來。

switch 語句

switch 語句用於基於不同條件執行不同動作,每一個 case 分支都是唯一的,從上至下逐一測試,直到匹配爲止。

在這裏插入圖片描述

與 C 語言不通,Golang 中的 switch 匹配項後面也不需要再加 break 語句。switch 默認情況下 case 最後自帶 break 語句,匹配成功後就不會執行其他 case。如果我們需要執行後面的 case,可以使用 fallthrough 語句。

格式:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

其中,變量 var1 可以是任何類型,而 val1 和 val2 則是同類型的任意值,類型不被侷限於常量或整數,但必須是相同的類型。或者最終結果爲相同類型的表達式。如果希望通過布爾數據類型來進行判定,則 switch 關鍵字後不需要緊跟條件表達式。

同時,還可以同時測試多個可能符合條件的值,使用逗號分割它們,例如:case val1, val2, val3

示例:

package main

import "fmt"

func main() {

   /* 定義局部變量 */
   var grade string = "B"
   var marks int = 90

   switch marks {
      case 90:
          grade = "A"
      case 80:
          grade = "B"
      case 50,60,70 :
          grade = "C"
      default:
          grade = "D"  
   }

   switch {
      case grade == "A" :
         fmt.Printf("優秀!\n" )    
      case grade == "B", grade == "C" :
         fmt.Printf("良好\n" )      
      case grade == "D" :
         fmt.Printf("及格\n" )      
      case grade == "F":
         fmt.Printf("不及格\n" )
      default:
         fmt.Printf("差\n" );
   }
   fmt.Printf("你的等級是 %s\n", grade );      
}

fallthrough 語句

在 switch 中使用 fallthrough 會強制執行後面的 case 語句,fallthrough 不會判斷下一條 case 的表達式結果是否爲 true。

示例:

package main

import "fmt"

func main() {

    switch {
        case false:
            fmt.Println("1、case 條件語句爲 false")
            fallthrough
        case true:
            fmt.Println("2、case 條件語句爲 true")
            fallthrough
        case false:
            fmt.Println("3、case 條件語句爲 false")
            fallthrough
        case true:
            fmt.Println("4、case 條件語句爲 true")
        case false:
            fmt.Println("5、case 條件語句爲 false")
            fallthrough
    default:
            fmt.Println("6、默認 case")
    }
}

結果:

2、case 條件語句爲 true
3、case 條件語句爲 false
4、case 條件語句爲 true

type-switch 語句

Golang 中,還可以使用 type-switch 來判斷某個 interface(接口)變量中實際存儲的變量類型。

格式:

switch x.(type) {
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定義任意個數的case */
    default: /* 可選 */
       statement(s);
}

示例:

package main

import "fmt"

func main() {
   var x interface{}
     
   switch i := x.(type) {
      case nil:  
         fmt.Printf(" x 的類型 :%T", i)                
      case int:  
         fmt.Printf("x 是 int 型")                      
      case float64:
         fmt.Printf("x 是 float64 型")          
      case func(int) float64:
         fmt.Printf("x 是 func(int) 型")                      
      case bool, string:
         fmt.Printf("x 是 bool 或 string 型" )      
      default:
         fmt.Printf("未知型")    
   }  
}

select(開關)語句

select 語句類似於用於通信的 switch 語句。區別在於 select 語句是專爲 channel(通道)而設計的,每個 case 必須是一個通信操作,要麼是發送(ch <- )要麼是接收(<- ch)。

select 隨機執行一個可運行的 case。如果沒有可運行的 case,它將阻塞,直到有 case 可運行。其中,default 子句應該總是可運行的。

  • 每個 case 都必須是一個通信操作(communication clause)。
  • 所有 channel 表達式都會被求值。
  • 所有被髮送的表達式都會被求值。
  • 如果任意某個通信可以進行,它就執行,其他則被忽略。
  • 如果有多個 case 都可以運行,select 會隨機公平地選出一個執行。其他不會執行。否則:
    • 如果有 default 子句,則執行該語句。
    • 如果沒有 default 子句,select 將阻塞,直到某個通信可以運行;Golang 不會重新對 channel 或值進行求值。

格式:

elect {
    case communication clause:
       statement(s);      
    case communication clause:
       statement(s);
    /* 你可以定義任意數量的 case */
    default: /* 可選 */
       statement(s);
}

示例:

package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}

簡而言之,select 會循環檢測所有 case 的條件表達式,如果有滿足則執行並退出,否則一直循環檢測

package main

import (
    "fmt"
    "time"
)

func Chann(ch chan int, stopCh chan bool) {
    var i int
    i = 10
    for j := 0; j < 10; j++ {
        ch <- i
        time.Sleep(time.Second)
    }
    stopCh <- true
}

func main() {

    ch := make(chan int)
    c := 0
    stopCh := make(chan bool)

    go Chann(ch, stopCh)

    for {
        select {
            case c = <- ch:
                fmt.Println("Recvice c:", c)
                fmt.Println("channel")
            case s := <- ch:
                fmt.Println("Receive s:", s)
            case _ = <- stopCh:
                goto end
        }
    }
end:
}

結果:

Recvice c: 10
channel
Receive s: 10
Recvice c: 10
channel
Receive s: 10
Receive s: 10
Recvice c: 10
channel
Receive s: 10
Receive s: 10
Recvice c: 10
channel
Recvice c: 10
channel

循環

for 循環語句

在這裏插入圖片描述

Golang 僅支持 for 循環,但 Golang 的 for 循環具有 3 種形式。

  1. 和 C 語言的 for 一樣,但循環控制語句不需要使用 “()” 括起來:
for init; condition; post { }
  • init:一般爲賦值表達式,給控制變量賦初值;
  • condition:關係表達式或邏輯表達式,循環控制條件;
  • post:一般爲賦值表達式,給控制變量增量或減量。

for 循環的執行過程如下:

  1. 先對 init 賦初值;
  2. 判別賦值表達式 init 是否滿足 condition 條件,若其值爲真,則執行循環體內語句,然後執行 post。進入第二次循環,再判別 condition;否則判斷 condition 的值爲假,不滿足條件,就終止 for 循環,執行循環體外語句。

示例:計算 1 到 10 的數字之和

package main

import "fmt"

func main() {
        sum := 0
        for i := 0; i <= 10; i++ {
                sum += i
        }
        fmt.Println(sum)
}
  1. 和 C 的 while 循環一樣,省略 init 和 post:
for condition { }

示例:

package main

import "fmt"

func main() {
    sum := 1
    
    for sum <= 10 {
         sum += sum
    }
    fmt.Println(sum)
}
  1. 和 C 的 for(;;) 一樣,省略 init、condition 和 post:
for { }

示例,無限循環

package main

import "fmt"

func main() {
    sum := 0
    for {
        sum++        // 無限循環下去
    }
    fmt.Println(sum) // 無法輸出
}

For-each range 循環語句

Golang 提供了 range(範圍)關鍵字,用於 for 循環中迭代字符串、數組(Array)、切片(Slice)、通道(Channel)或集合(Map)中所含有的元素。

  • 數組、切片:返回元素的索引和索引對應的值
  • 集合:返回 key/value 對。

格式:

for key, value := range oldMap {
    newMap[key] = value
}

示例:For-each range 循環,這種格式的循環可以對 Slice、Map、數組、字符串進行迭代輸出各個元素。

package main
import "fmt"

func main() {
    // 定義數組
    strings := []string{"google", "runoob"}
    for i, s := range strings {
        fmt.Println(i, s)
    }
    
    // 定義數組
    numbers := [6]int{1, 2, 3, 5}
    for i, x := range numbers {
        fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
    }  
}

結果:

0 google
1 runoob
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0

示例:

package main

import "fmt"

func main() {

    // 這是我們使用 range 去求一個 slice 的和,使用數組跟這個很類似。
    nums := []int{2, 3, 4}
    sum := 0

    // 在數組上使用 range 將傳入 index 和 value 兩個變量。
    // 上面那個例子我們不需要使用該元素的序號,所以我們使用空白符 _ 省略了。有時侯我們確實需要知道它的索引。
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)
    
    for i, num := range nums {
        if num == 3 {
            fmt.Println("index:", i)
        }
    }
    
    // range 也可以用在 map 的鍵值對上。
    kvs := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }
    
    // range 也可以用來枚舉 Unicode 字符串。第一個參數是字符的索引,第二個是字符(Unicode的值)本身。
    for i, c := range "go" {
        fmt.Println(i, c)
    }
}

結果:

sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111

循環控制語句

break 語句

在這裏插入圖片描述

  1. 用於循環語句中跳出循環,並開始執行循環之後的語句。
  2. break 在 switch 語句中在執行一條 case 後跳出。
  3. 在多重循環中,可以用標號 label 標出想跳出的循環。

示例:

package main

import "fmt"

func main() {

    // 不使用 label 標記
    fmt.Println("---- break ----")
    for i := 1; i <= 3; i++ {
        fmt.Printf("i: %d\n", i)
        for i2 := 11; i2 <= 13; i2++ {
            fmt.Printf("i2: %d\n", i2)
            break
        }
     }

    // 使用 label 標記,常見於跳出潛逃循環。
    fmt.Println("---- break label ----")
    re:
        for i := 1; i <= 3; i++ {
            fmt.Printf("i: %d\n", i)
            for i2 := 11; i2 <= 13; i2++ {
                fmt.Printf("i2: %d\n", i2)
                break re
            }
        }
}

continue 語句

在這裏插入圖片描述

與 breck 不同,continue 不是跳出循環,而是跳過當前循環並執行下一次循環。所以,在 for 循環中,執行 continue 語句同樣會觸發 for 增量語句的執行。

在多重循環中,同樣可以用標號 label 標出想 continue 的循環。

示例:

package main

import "fmt"

func main() {

    // 不使用 label 標記
    fmt.Println("---- continue ---- ")
    for i := 1; i <= 3; i++ {
        fmt.Printf("i: %d\n", i)
        for i2 := 11; i2 <= 13; i2++ {
            fmt.Printf("i2: %d\n", i2)
            continue
        }
    }

    // 使用標記
    fmt.Println("---- continue label ----")
    re:
        for i := 1; i <= 3; i++ {
            fmt.Printf("i: %d\n", i)
            for i2 := 11; i2 <= 13; i2++ {
                fmt.Printf("i2: %d\n", i2)
                continue re
            }
        }
}

goto 語句

在這裏插入圖片描述

與 C 語言類似的,goto 語句可以無條件地轉移到過程中指定的行。goto 語句通常與條件語句配合使用。可用來實現條件轉移,構成循環,跳出循環體等功能。

通常的,在結構化程序設計中一般不主張使用 goto 語句,以免造成程序流程的混亂,使理解和調試程序都產生困難。

格式:

goto label;
..
.
label:
    statement(s);

示例:在變量 a 等於 15 的時候跳過本次循環並回到循環的開始語句 LOOP 處

package main

import "fmt"

func main() {
   /* 定義局部變量 */
   var a int = 10

   /* 循環 */
   LOOP: for a < 20 {
      if a == 15 {
         /* 跳過迭代 */
         a = a + 1
         goto LOOP
      }
      fmt.Printf("a的值爲 : %d\n", a)
      a++    
   }  
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章