目錄
文章目錄
條件判斷
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 種形式。
- 和 C 語言的 for 一樣,但循環控制語句不需要使用 “()” 括起來:
for init; condition; post { }
- init:一般爲賦值表達式,給控制變量賦初值;
- condition:關係表達式或邏輯表達式,循環控制條件;
- post:一般爲賦值表達式,給控制變量增量或減量。
for 循環的執行過程如下:
- 先對 init 賦初值;
- 判別賦值表達式 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)
}
- 和 C 的 while 循環一樣,省略 init 和 post:
for condition { }
示例:
package main
import "fmt"
func main() {
sum := 1
for sum <= 10 {
sum += sum
}
fmt.Println(sum)
}
- 和 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 語句
- 用於循環語句中跳出循環,並開始執行循環之後的語句。
- break 在 switch 語句中在執行一條 case 後跳出。
- 在多重循環中,可以用標號 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++
}
}