1.概述
代碼的執(zhí)行順序传蹈,有 3 大類押逼,為:
- 順序,從上到下依次執(zhí)行卡睦,基礎(chǔ)流程(核心流程)
- 循環(huán)宴胧,某段代碼重復(fù)執(zhí)行。
- 分支表锻,選擇性執(zhí)行某段代碼恕齐。
2.流程圖回顧
使用如下的典型圖例,描述流程節(jié)點(diǎn):
-
橢圓,表示開始和結(jié)束:
-
矩形显歧,表示某個(gè)具體的進(jìn)程步驟:
-
菱形仪或,表示條件判斷:
3. 分支if
1) 語法
- 語法 1,只有 if 語句
// 語法 1士骤,條件成立范删,執(zhí)行語句塊內(nèi)容
if condition {
// 語句塊
}
- 語法 2,if + else
// 語法 2拷肌,條件成立到旦,執(zhí)行 if 語句塊,否則執(zhí)行 else 語句塊
if condition {
// if 語句塊
} else {
// else 語句塊
}
- 語法 3巨缘,else if
// 語法 3添忘,條件 1 成立,執(zhí)行語句塊 1 然后結(jié)束若锁,若條件 1 不成立搁骑,繼 續(xù)判斷條件 2,若成立執(zhí)行語句塊 2 然后結(jié)束又固。直到全部條件判斷完畢仲器。
condition1, condition2, conditionN := true, true, true
if condition1 {
/ / 語句塊 1
} else if condition2 {
// 語句塊 2
} else if conditionN {
// 語句塊 N
}
- 語法 4,else if else
// 語法 4仰冠,與語法 3 一致乏冀,多一個(gè) else 語句塊,當(dāng)全部條件不滿足時(shí)洋只,執(zhí)行 else 語句塊
if condition1 {
// 語句塊 1
} else if condition2 {
// 語句塊 2
} else if conditionN {
// 語句塊 N
} else {
// else 語句塊
}
- 條件表達(dá)式為布爾表達(dá)式
條件表達(dá)式一定是可以返回布爾值的表達(dá)式煤辨。不能直接判斷 0,”” 這種非布爾類型數(shù)
據(jù)木张,沒有自動(dòng)向布爾值轉(zhuǎn)換的過程众辨,下面的語法是不對(duì)的:
if 0 {
// non-bool 0 (type int) used as if condition
fmt.Println("if statement block")
}
- 支持條件初始化語句
在 if 后,支持先完成條件初始化舷礼,再去完成條件表達(dá)式的語法鹃彻,結(jié)構(gòu)為:
if 條件初始化語句;條件表達(dá)式 {
}
if condition := 10>8; condition {
fmt.Println("使用條件初始化語句")
fmt.Println("條件成立")
}
注意:以上結(jié)構(gòu)中,條件的是否成立妻献,僅僅與條件表達(dá)式相關(guān)蛛株,與條件初始化語句無關(guān)。
if c:=10<8;true{
fmt.Println(c)
fmt.Println("使用條件初始化語句")
fmt.Println("條件成立")
}
// false
// 使用條件初始化語句
// 條件成立
注意:使用條件初始化的意思育拨,主要是為了將判斷條件變量的作用域(有效區(qū)域)限定在 if 語句 范圍內(nèi)(縮小變量有效作用域策略)谨履, condition2,在 if 外無效熬丧。
if condition2 := 10>8; condition2 {
fmt.Println("使用條件初始化語句")
fmt.Println("條件成立")
fmt.Println(condition2)
}
fmt.Println(condition2) //undefined: condition2
4.分支 switch
1) if 和 switch 的差異?
if笋粟,條件分支,利用條件表達(dá)式確定條件是否成立。
switch害捕,狀態(tài)分支绿淋,利用狀態(tài)值確定分支條件。
代碼演示:
// score >= 80 就是條件
score := 98
if score >= 90 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else if score >=60 {
fmt.Println("C")
} else {
fmt.Println("呵呵")
}
// int尝盼,string吞滞,bool,就是特定的狀態(tài)!
switch d := 10; d {
case 9 :
fmt.Println(9)
case 10 :
fmt.Println(10)
case 11 :
fmt.Println(11)
default:
fmt.Println("default")
}
2) 語法盾沫,switch case default
value := 4
switch value {
default:
fmt.Println("six")
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
//...
case 3, 4, 5: // value == 3 || value == 4 || value == 5
fmt.Println("three, four, five") }
執(zhí)行流程是裁赠,判斷 switch 表達(dá)式的值與 case 給定的狀態(tài)是否相等,相等則執(zhí)行對(duì)應(yīng)的語句 塊赴精,然后 switch 結(jié)束组贺。
注意,多個(gè)狀態(tài)值祖娘,可以在一個(gè) case 中描述。
注意啊奄,若沒有任何 case 匹配渐苏,則會(huì)執(zhí)行 default 分支。前提是存在 default 分支菇夸。(default 分
支是可選的)琼富。default 的位置無關(guān)。
在 switch 表達(dá)式中庄新,同樣支持初始化表達(dá)式鞠眉。 支持:
switch 初始化表達(dá)式; switch 表達(dá)式 {
}
目的是將條件分支值變量的有效作用域控制在 switch 語句的范圍內(nèi),避免全局污染!
代碼演示:
switch value := 4; value {
default:
fmt.Println("six")
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
//...
case 3, 4, 5: // value == 3 || value == 4 || value == 5
fmt.Println("three, four, five")
}
fmt.Println(value) //undefined: value
格外注意的是择诈,switch 的 switch 表達(dá)式是也可以省略的械蹋。(if 的條件表達(dá)式是不能省略的。) 省略后羞芍,case 應(yīng)該使用條件語句完成分支判斷哗戈,不能再使用狀態(tài)值了,因?yàn)闆]有值可以用
于判定了荷科。
switch value := 4; {
default:
fmt.Println(value)
fmt.Println("six")
case value == 1:
fmt.Println("one")
case value == 2:
fmt.Println("two")
case value == 3 || value == 4 || value == 5:
fmt.Println("three, four, five")
}
3) fallthrough唯咬,穿越到下個(gè) case 塊
go 的 switch case 在滿足了一個(gè) case 后,執(zhí)行對(duì)應(yīng)的語句塊畏浆,之后 swtich 直接結(jié)束胆胰。
與很多其他語言不通的是,很多其他語句的 swtich 當(dāng) case 滿足后會(huì)依次執(zhí)行余下的 全部語句塊刻获。
為了在語法上與其他語言類似蜀涨,go 提供了 fallthrough 語句,用于在 case 語句塊間穿越。 當(dāng) case 語句塊的最后的語句為 fallthrought 時(shí)勉盅,會(huì)執(zhí)行下一個(gè) case 語句塊:
switch value := 2; value {
default:
fmt.Println("six")
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
fallthrough //
//...
case 3, 4, 5: // value == 3 || value == 4 || value == 5
fmt.Println("three, four, five")
//fallthrough // 最后一個(gè)語句塊中不能存在 fallthrough
}
// 輸出 two
// three, four, five
注意:
fallthrough 只能是語句塊的最后一條語句佑颇。
而且最后一個(gè)語句塊中不能存在 fallthrough。
若執(zhí)行的語句塊不存在 fallthrough草娜,會(huì)停止穿越!
4) switch interface.(type) 結(jié)構(gòu)挑胸,type switch
該結(jié)構(gòu)可以完成類型檢測(cè),執(zhí)行對(duì)應(yīng)的代碼宰闰。
// 類型檢測(cè)
var x interface{}
//x = 42
x = "hank"
//x = false
//
switch d := x.(type) {
case int:
fmt.Println(d, d+42)
case string:
fmt.Println(d, d + " GoLang")
//fallthrough //cannot fallthrough in type switch
case bool:
fmt.Println(d, !d)
}
該結(jié)構(gòu)也是 swtich 的語法茬贵。
特殊性在于: 不支持 falltrhrough。
5. 循環(huán) for
1) 概述
基于循環(huán)條件移袍,重復(fù)執(zhí)行代碼塊的結(jié)構(gòu)解藻。 流程圖上,通常是一個(gè)閉合的環(huán)葡盗。
語法上使用 for 完成循環(huán)結(jié)構(gòu)螟左。(go 語言中沒有 while 結(jié)構(gòu)循環(huán))
2) 基本語法
for 條件初始化語句;條件表達(dá)式;條件更新語句{
//循環(huán)體
}
for i:=0; i<10; i++ {
fmt.Println(i)
}
for 存在三個(gè)循環(huán)條件部分,初始化觅够,條件判斷胶背,條件變化。
若 循環(huán)體執(zhí)行了 N 次喘先,那么:
- 條件初始化執(zhí)行 1 次钳吟。
- 條件判斷執(zhí)行 N+1 次。
- 條件變化執(zhí)行 N 次窘拯。
可見红且,應(yīng)該將條件數(shù)據(jù)放在初始化中完成,避免重復(fù)執(zhí)行涤姊,例如暇番,當(dāng)使用 i 作為索引, 遍歷數(shù)組或切片的時(shí)候思喊,語法為:
arr := [...]int{42, 1024, 365, 2048, 1, 36, 88, 66}
for i, l := 0, len(arr); i<l; i++ {
fmt.Println(i, arr[i])
}
// 不建議的語法
for i := 0; i<len(arr); i++ {
fmt.Println(i, arr[i])
}
3) 條件循環(huán)語法(其他語言的 while 語法)
for 條件表達(dá)式 {
}
result, n := 0, 0
for result <= 100 {
n ++
result += n
}
fmt.Println(result)
條件的數(shù)據(jù)依賴于外部數(shù)據(jù)完成奔誓。
通常循環(huán)體內(nèi)部,要完成循環(huán)條件的更新搔涝。
4) 無限循環(huán)語法
for {
}
i := 0
for { // for true {
fmt.Println(i) i ++
if i >= 10 {
break // 強(qiáng)制 for 終止
}
}
不需要 循環(huán)條件厨喂,表示條件永遠(yuǎn)為 true。 意味著庄呈,循環(huán)體會(huì)無限次數(shù)的循環(huán)執(zhí)行下去蜕煌。
通常,需要配合循環(huán)體內(nèi)部的條件變化以及在循環(huán)體內(nèi)部強(qiáng)制終止來實(shí)現(xiàn)诬留。上面的 break
結(jié)構(gòu)斜纪。
該結(jié)構(gòu)通常用于實(shí)現(xiàn)守護(hù)進(jìn)程贫母。需要一直運(yùn)行的程序。
6. 循環(huán)遍歷盒刚,for range
適用于遍歷:array腺劣,slice,map 復(fù)合結(jié)構(gòu)因块。
語法一致:
for i, v := range data {
}
for i := range data {
}
for _, v := range data {
}
7. 注意橘原,語句塊的左大括號(hào),與語句標(biāo)簽在一行
for ;; {
if ; {
swtich ; {
for := range {
\\ 不能是:
for ;;
{
if ;
{
switch ;
{
// 包括函數(shù)的大括號(hào)涡上,也需要與函數(shù)聲明在一行趾断。
func funcName() {
8. goto label
label: 語句標(biāo)簽。類似于路標(biāo)吩愧,用于標(biāo)識(shí)代碼位置芋酌。
使用 goto 語句可以跳轉(zhuǎn)到特定的 label 位置。
演示雁佳,例如在處理錯(cuò)誤時(shí):
// 錯(cuò)誤處理
// 可能的錯(cuò)誤有很多種脐帝,逐一檢測(cè)。
// 一旦檢測(cè)到任意的錯(cuò)誤糖权,則立即處理錯(cuò)誤堵腹,不再檢測(cè)后續(xù)的錯(cuò)誤,邏輯如
下:
if error1 {
goto errorLabel
}
if error2 {
goto errorLabel
}
if error3 { //標(biāo)簽跳轉(zhuǎn)
goto errorLabel
}
errorLabel: // 標(biāo)簽定義
fmt.Println("error processing")
上面的語法中温兼,涉及到了:
- 定義標(biāo)簽: 為標(biāo)簽設(shè)置特定的名字,滿足標(biāo)識(shí)符定義即可武契。
- 使用標(biāo)簽: 完成募判。 跳轉(zhuǎn)標(biāo)簽:使用 goto 完成跳轉(zhuǎn)。
注意: 跳轉(zhuǎn) goto咒唆,不是任意跳轉(zhuǎn)届垫。跳轉(zhuǎn)的目標(biāo)不是任何位置都可達(dá)到,例如: 不能跨函數(shù)跳轉(zhuǎn)全释。
不能跳轉(zhuǎn)到內(nèi)部的語句塊中装处。
總結(jié)下來:標(biāo)識(shí)符必須可見,才可以 goto 成功浸船。
標(biāo)識(shí)符可見的語法: 語句塊嵌套的可見性妄迁。內(nèi)層可以看見外層,但是外層看不到內(nèi)層李命。
不同的語句塊也不可以跳轉(zhuǎn)登淘。
func main() {
goto labelName
// 內(nèi)層可以看見外層,但是外層看不到內(nèi)層封字。
for i:=0;i<10;i++ {
labelName: // XXX 不可
fmt.Println()
}
}
// 不同的語句塊也不可以跳轉(zhuǎn)黔州。
func F() {
labelName: // XXX 不可
fmt.Println()
}
9. break耍鬓,強(qiáng)行終止循環(huán)執(zhí)行
break 用于循環(huán)內(nèi)部,當(dāng)執(zhí)行到 break 時(shí)流妻,會(huì)終止 break 所在的循環(huán)的執(zhí)行牲蜀。
代碼演示
for i:=0; i<10; i++ {
if i == 6 {
break
}
fmt.Println(i)
}
以上結(jié)果,6 及后續(xù)數(shù)字沒有輸出绅这。執(zhí)行到了 break涣达,會(huì)立即終止。
10.continue君躺,強(qiáng)行終止本次循環(huán)體執(zhí)行峭判,循環(huán)繼續(xù)
continue,僅僅終止本次循環(huán)體執(zhí)行棕叫。但是 for 的整體循環(huán)并沒有結(jié)束林螃,會(huì)繼續(xù)修改循
環(huán)條件,執(zhí)行下一次循環(huán)體俺泣。
代碼演示:
for i:=0; i<10; i++ {
if i == 6 {
continue
}
fmt.Println(i)
}
以上的結(jié)果疗认,沒有 6 的輸出。continue 之后的代碼伏钠,不會(huì)繼續(xù)執(zhí)行横漏,而是指向下一次 i== 7 的循環(huán)體。
11.break 或 continue 多重循環(huán)
當(dāng)循環(huán)語句出現(xiàn)嵌套時(shí)熟掂,若需要在內(nèi)部循環(huán)體中缎浇,直接終止外部的循環(huán)執(zhí)行,則需要配
合 標(biāo)簽 語法完成終止赴肚。 演示:
outerLabel:
for i:=0; i<3; i++ {
for j:=0; j<3; j++ {
if i + j > 2{
break outerLabel
}
fmt.Println(i, j)
}
}
此時(shí)素跺,break outerLabel, 會(huì)導(dǎo)致 outerLabel 對(duì)應(yīng)的 for 全部終止! 否則,break誉券,僅僅會(huì)終止 所在的 for j 的執(zhí)行指厌,而不會(huì)終止 for i 的執(zhí)行。
12.switch 中的 break 一定要使用標(biāo)簽
for 中使用 switch 結(jié)構(gòu)判斷執(zhí)行 break踊跟,需要使用標(biāo)簽語法踩验。
代碼演示:
forLabel:
for i:=0; i<10; i++ {
switch i {
case 6:
break forLabel
}
// if i == 6 {
// break
// }
fmt.Println(i)
}
若不使用標(biāo)簽語法,switch 中的 break 不會(huì)終止循環(huán)商玫。
原因箕憾,switch 中的 break,是終止 switch 的作用拳昌。在實(shí)現(xiàn) switch 時(shí)厕九,被視為循環(huán)結(jié)構(gòu)。