Go 程式設計教學:控制流程 (Control Structure) - 選擇 (Selection)

PUBLISHED ON SEP 14, 2017 — PROGRAMMING

到目前為止,我們的程式都是依序執行;在程式中加入控制結構 (control structure) 後,程式就可以依條件決定是否要執行某區塊的程式碼,也可以重覆多次執行同區塊的程式碼,這時候,程式好像變聰明了。

控制結構分為兩種,分別是:

  • 選擇 (selection):選擇性執行
  • 迭代 (iteration):重覆執行

在本文中,我們會介紹 Go 可用的選擇控制結構。

if

條件控制的作用在判斷程式的狀態,符合特定條件時,才執行該區塊內的程式碼,使得程式可以依不同狀態改變其行為。if 在英文中原本就是「如果」的意思,大部分的程式語言都用 if 當關鍵字,Go 也不例外。

如果我們用 Go 虛擬碼 (pseudocode) 表示如下:

if condition {
    // Do something here.
}

以下是實例:

package main
 
import (
    "fmt"
)
 
func main() {
    x := 10
 
    if x > 0 {
        fmt.Println("x is larger than zero")
    }
}

除了單一的 if 外,還可以加入 else 區塊, 將其寫成虛擬碼如下:

if condition {
    // Do something here.
} else {
    // Do something here.
}

以下是實例:

package main
 
import (
    "fmt"
)
 
func main() {
    x := 3
 
    if x > 10 {
        fmt.Println("x is larger than 10")
    } else {
        fmt.Println("x is not larger than 10")
    }
}

另外,還可以加入一個或以上的 else if 區塊,將其寫成虛擬碼如下:

if condition_a {
    // Do something_a here.
} else if condition_b {
    // Do something_b here.
} else {
    // Do something.
}

以下是實例:

package main
 
import (
    "fmt"
)
 
func main() {
    n := 0
 
    if n > 0 {
        fmt.Println("n is larger than zero.")
    } else if n < 0 {
        fmt.Println("n is smaller than zero.")
    } else {
        fmt.Println("n is equal to zero.")
    }
}

在使用多個 if 敘述時,若滿足了某一個條件,程式即會進入該條件所在的區塊,執行該區塊的程式碼,接著跳出。要注意這個特性,以免寫出語法對,但邏輯錯的程式。以下實例使用多個 else if

package main
 
import (
    "fmt"
)
 
func main() {
    score := 88
 
    if score >= 90 {
        fmt.Println("A")
    } else if score >= 80 {
        fmt.Println("B")
    } else if score >= 70 {
        fmt.Println("C")
    } else if score >= 60 {
        fmt.Println("D")
    } else {
        fmt.Println("F")
    }
}

switch

Go 提供 switch 做為另一個條件判斷的語法。基本上,switch 可視為一種語法糖 (syntactic sugar),因為所有的 switch 語法都可以用等效的 if 語法來代替,但適當地使用 switch 會使得程式碼比較簡潔,而 C 家族的程式語言都保留 switch 這個語法,所以 Go 也就將 switch 保留下來。

switch 的 Go 虛擬碼如下:

switch (value) {
case a:
    // Do something_a
case b:
    fallthrough  // Explict fallthrough in Go.
case c:
    // Do something_c.
default:
    // Do something.
}

以下程式判斷該程式執行當下所用的系統:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Print("Go runs on ")
	os := runtime.GOOS
	switch os {
	case "windows":
		fmt.Println("Windows")
	case "darwin":
		fmt.Println("Mac")
	case "linux":
		fmt.Println("GNU/Linux")
	default:
		// freebsd, openbsd, plan9...
		fmt.Printf("%s.", os)
	}
}

在上例中,default 的意思是如果不符合其他選項,就使用這個選項,類似 else 敘述,不是必需的。如同 if 般,Go 的 switch 也是由上而下依序執行。見以下實例:

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("When's Saturday?")

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

在 C 語言中,switch 有一個易引起錯誤的 switch「特性」叫 fallthrough,簡單的說,這是因為沒在 case 區塊尾端加入 break 敘述,執行到另一個 case 區塊的程式碼所引發的行為;雖然 fallthrough 是語法特性,也很容易變成 bug。在 Go 裡面,為了預防這個 bug,取消這個特性,如果程式設計者需要這個特性,需明確加上 fallthrough 敘述。見以下實例:

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now().Weekday()

	switch now {
	case time.Saturday:
		fallthrough
	case time.Sunday:
		fmt.Println("Weekend")
	case time.Friday:
		fmt.Println("Thank God. It's Friday")
	case time.Wednesday:
		fmt.Println("Hump day")
	default:
		fmt.Println("Week")
	}
}

switch 也可以不加變數,這時候,switch 就像是另一個 if。見以下實例:

package main

import (
	"fmt"
)

func main() {
	score := 88

	switch {
	case score >= 90:
		fmt.Println("A")
	case score >= 80:
		fmt.Println("B")
	case score >= 70:
		fmt.Println("C")
	case score >= 60:
		fmt.Println("D")
	default:
		fmt.Println("F")
	}
}

在這種情形下,使用 if 或是 switch 僅是個人偏好。

在本文中,我們介紹 ifswitch 兩種條件控制的語法,建議讀者可以試著將本文的範例分別以 if 和 switch 改寫,就可以體會在什麼情形下使用何種語法較合適。在下一篇文章中,我們會介紹迴圈。

comments powered by Disqus