4. Go 程序结构控制

当编写一个有一丢丢难度的程序的时候,就一定会涉及到程序结构(流向)的控制:需要一步一步顺序执行;需要根据不同情况进行选择,运行不同的代码;对相同的重复的事情,循环重复N次;两段代码同时运行,要可能要修改某一个变量值,但到底谁可以在什么时间、什么情况改需要精细控制。

在Go中,为了完成上述程序执行逻辑的控制,需要用的if, for, switch, func, select等内容,逐个来看。

顺序结构

Go 默认会按照顺序结构执行,即按照 main() 函数的语句的顺序,一条一条执行,直到执行碰到return 正常退出程序,或遇到程序异常,异常退出程序。当程序执行到函数main() 中遇到另外一个函数时,系统就会将main 函数的执行状态保存到一个叫”栈“的数据结构中,跳出main函数,去执行函数FuncA,在FuncA中遇到函数 FuncB 也一样。等函数FuncB 执行完成后,会返回FuncA,系统会从栈中找到FuncA 的信息并恢复,继续执行FuncA,知道FuncA返回,然后需要执行 main() 函数,直到 main() 完成,"交还"系统控制权。

函数调用结构.png

栈是一种数据结构,具有”先进后出“(FILO)这样的特性,更多细节可以参考维基百科

选择结构

当任务遇到不同的情况需要不同处理时,就需要用到 if 语句;当然还有其一家兄弟if..else if...else

if condition{

    /* true logic code */

} // condition满足就执行,否则不执行,执行下面的。
//最为常见的是错误处理,如果有错误就进行错误处理,没错误就继续

if condition{   

    /* true logic code */

}else {

    /* false logic code */

}// 条件满足就执行true逻辑,否则执行false逻辑。

if conditionA{

    /* A condition */ 

}else if conditionB{

    /*B condition */    

}else if conditionC{

    /*C condition */    

}else{

    /* other condition*/

}// 多条件就从上往下逐个执行,如果条件都不满足,就执行else。 
//还记得90-100评A,80-90评B,...吗?

if else 除了上述用法以外,还可以嵌套执行,就是如下的效果,用于复杂的条件判定。

if conditionA{
    if conditonA.1 {
        //A.1
    }else {
        //A.x(x!=1)
    }
}else{
    // !A
}

上述特性,其他语言一般都会提供,Go中还提供一种方式是if statement;conditon{} 其中 statement 是一个简短的声明或赋值,用于获取condition变量的值。与statement; if conditon{} 区别是什么呢?……作用域。作用域是一种表明变量或函数等可见范围与时间的描述。刚刚if语句中,如果statementif中,则statement中变量作用范围是该 if 块中,一旦离开if,就无法访问。而 statementif 外,则上下文对其变量都可以看到或修改。Go 中有一个原则,与含义不相关的简单变量使用简短名称定义,并且其作用域最小,这样就可以多处重复利用这些简短名称,且不会影响程序执行。最为常见到例子就是错误状态判断,在数据类型中map一节中,我们知道查询一个key会返回两个值,一个值本身,另外一个是值的状态。一个大的程序中有很多错误情况要判断,此时都可以通过 if value, ok := mapName[key];!ok{/*do something*/}

多选择结构

除了if...else外,还有一种选择结构叫 switch ,它通过用于很多个情况的选择,用来替代复杂的if...else if...elseif...elseswitch 一般情况下,是后面跟有一个变量,case condition 对变量取值进行判断,满足则执行,执行完当前条件,退出 switch; 如果除 default 外的条件都不满足,那就执行defalut语句,如果没有defalut语句,那就直接跳过 switch。如果一个语句可以应对多个condition,则可以使用逗号,将所有满足条件的罗列出来。

switch V{
    case conditonA:
        //statement
    case conditonB, conditonC, conditionD:
        //statemtnt
    case conditionE:
        // statement
    default:
        // statement
}

switch 还有一种特殊情况,就是没有变量 v ,那么变量可以直接在condition中表达,就更像if else

如果执行完第一个case,还想继续向下判断,那么可以通过 fallthrough 来继续测试后面的case条件,满足则再次执行

// 成绩score
switch {
    case score < 60 && score >= 60:
        fmt.Printf("不及格,D\n")
    case score >= 60:
        fmt.Printf("及格,")
        fallthrough
    case score >=70 && score < 80  :
        fmt.Println("C\n")
    case score >=80 && score < 90:
        fmt.Println("B\n")
    case score >=90 && score <= 100:
        fmt.Println("A\n")
    default:
        fmt.Println("录错成绩了,别激动!")
}

循环结构

循环,就是重复执行某一个需要重复的工作,例如一堆数据中找最大,或者单纯的想看看这个数据集。如果循环没没有退出条件的限制,最简单后果是CPU使用率一直很高,或者内存被消耗尽,也或者你设计良好,它默默的一直干活,总之设计循环退出条件是一件聪明的事情,可以在任意情况下选择退出,尽管你可以把退出条件设置的比较隐蔽。

Go 循环只有一种叫做for, 没有其他。for 结构:

for init;condition;post{
    /* do something */ 
}

其中 init为变量初始化条件,如果if 一样,在for 结构声明的变量,只能在该块中调用,初始化条件只执行一次;在初始化完成后,for 开始判断condition 是否满足,如果条件满足,则执行循环块;执行完循环后执行post 语句。然后继续检查条件是否满足,重复下去,直到条件不满足,退出循环条件。如果初始化条件声明在for 之外,初始化条件可以跳过;如果post语句在循环中执行,那么post 也可以省略;如果看到下面的循环中断关键字 break,可以用来手动判断是否退出,那么condition 也可以省略。

中断循环的关键字 break ,当程序执行到循环中的break 语句时,循环退出

跳出当前循环的关键字 continue, 当程序执行到循环中的 continue 时,循环剩下的语句将被跳过,执行post,开始下一次循环,计算循环条件。

package main

import  "fmt"

func main() {
    for i := 1; i <= 5; i++ {
        for j := 1; j <= i; j++ {
            if i == 4 && j == 2 {
                fmt.Printf("\t\t") //当碰到i=4,j=2的时候,则打印两个制表符
                continue // 跳出本地循环,即不打印下面 2x4=8这一项
            }
            fmt.Printf("%d x %d = %d\t", j, i, i*j)
        }
        fmt.Println()
    }
}
/* another
内部for循环还可以写为
--------------version 1-------------------
for i := 1; i <= 5; i++ {
        j := 1
        for ; j <= i; j++ { // 虽然省略了init,但是分号不可省,注意
            if i == 4 && j == 2 {
                fmt.Printf("\t\t")
                continue
            }
            fmt.Printf("%d x %d = %d\t", j, i, i*j)
        }
        fmt.Println()
    }
---------------version 2 -------------------
for i := 1; i <= 5; i++ {
        j := 1
        for j <= i {// 支持只有条件的for
            if i == 4 && j == 2 {
                fmt.Printf("\t\t")
                continue
            }
            fmt.Printf("%d x %d = %d\t", j, i, i*j)
            j++ // 还是要更新条件变量,否则真的时一直循环,直到死机或被系统强制结束
        }
        fmt.Println()
    }
--------------version 3 ------------------------
for i := 1; i <= 5; i++ {
        j := 1
        for { // 如果没有条件就一直循环,直到
            if j > i {
                break // 直到碰到break,break 可以通过if设置,如果没有if,那就没有循环
            }
            if i == 4 && j == 2 {
                fmt.Printf("\t\t")
                continue
            }
            fmt.Printf("%d x %d = %d\t", j, i, i*j)
            j++
        }
        fmt.Println()
    }
/* Result
1 x 1 = 1
1 x 2 = 2       2 x 2 = 4
1 x 3 = 3       2 x 3 = 6       3 x 3 = 9
1 x 4 = 4                       3 x 4 = 12      4 x 4 = 16
1 x 5 = 5       2 x 5 = 10      3 x 5 = 15      4 x 5 = 20      5 x 5 = 25
*/

需要注意的是,break只能退出当前循环,对于如上面嵌套循环,如果全部退出循环,则需要与嵌套循环数量完全一致的break语句。

这是一般程序结构控制,对于并发或者说多线程程序控制,更加复杂且难以预测。好消息是,Go 有原生并发支持,但不会再这一节展开。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容