Go基礎(chǔ)-010 流程控制

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)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末地回,一起剝皮案震驚了整個(gè)濱河市扁远,隨后出現(xiàn)的幾起案子俊鱼,更是在濱河造成了極大的恐慌,老刑警劉巖畅买,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件并闲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡谷羞,警方通過查閱死者的電腦和手機(jī)帝火,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來湃缎,“玉大人犀填,你說我怎么就攤上這事∩のィ” “怎么了九巡?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蹂季。 經(jīng)常有香客問我冕广,道長(zhǎng),這世上最難降的妖魔是什么偿洁? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任撒汉,我火速辦了婚禮,結(jié)果婚禮上涕滋,老公的妹妹穿的比我還像新娘睬辐。我一直安慰自己,他們只是感情好宾肺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布溯饵。 她就那樣靜靜地躺著,像睡著了一般爱榕。 火紅的嫁衣襯著肌膚如雪瓣喊。 梳的紋絲不亂的頭發(fā)上坡慌,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天黔酥,我揣著相機(jī)與錄音,去河邊找鬼洪橘。 笑死跪者,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熄求。 我是一名探鬼主播渣玲,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弟晚!你這毒婦竟也來了忘衍?” 一聲冷哼從身側(cè)響起逾苫,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枚钓,沒想到半個(gè)月后铅搓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搀捷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年星掰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫩舟。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡氢烘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出家厌,到底是詐尸還是另有隱情播玖,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布像街,位于F島的核電站黎棠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏镰绎。R本人自食惡果不足惜脓斩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畴栖。 院中可真熱鬧随静,春花似錦、人聲如沸吗讶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽照皆。三九已至重绷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間膜毁,已是汗流浹背昭卓。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘟滨,地道東北人候醒。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像杂瘸,于是被迫代替她去往敵國(guó)和親倒淫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Swift 提供了類似 C 語言的流程控制結(jié)構(gòu)败玉,包括可以多次執(zhí)行任務(wù)的for和while循環(huán)敌土,基于特定條件選擇執(zhí)行...
    窮人家的孩紙閱讀 693評(píng)論 1 1
  • [The Swift Programming Language 中文版]本頁包含內(nèi)容: Swift提供了多種流程控...
    風(fēng)林山火閱讀 559評(píng)論 0 0
  • Swift提供了多種控制流聲明镜硕。包括while循環(huán)來多次執(zhí)行一個(gè)任務(wù);if返干,guard和switch聲明來根據(jù)確定...
    BoomLee閱讀 1,939評(píng)論 0 3
  • 控制流 [TOC] Swift提供了多種流程控制結(jié)構(gòu)谦疾,包括可以多次執(zhí)行任務(wù)的while循環(huán),基于特定條件選擇執(zhí)行不...
    伍哥___閱讀 506評(píng)論 0 0
  • 本章將會(huì)介紹 控制流For-In 循環(huán)While 循環(huán)If 條件語句Switch 語句控制轉(zhuǎn)移語句 continu...
    寒橋閱讀 715評(píng)論 0 0