您的位置 首页 golang

Golang 学习笔记:流程控制


条件语句

Go语言没有do-while语句,而for语句拥有更广泛的含义和用途switch语句也有进一步的扩展,支持类型判断和初始化子句等。

常见的流程控制的关键字有:

  • defer:用于捕获异常和资源回收等工作
  • select:用于多支选择(配合通道使用)
  • go:用于异步启动 goroutine 并执行特定函数
  • if判断语句
func main() {    a := 15    if a < 20 {        fmt.Println("a小于20")    }    //顺序执行    fmt.Println("a的值是", a)}

if判断语句是最简单的判断,缺点在于无法返回false的情况,为了增加这一功能就要用到if-else语句。

  • if-else语句
func main() {    a := 20    if a < 20 {        fmt.Println("a小于20")    } else {        fmt.Println("a大于等于20")    }}

如果想判断a值是否大于10同时小于20时,if-else语句就不能够满足需求了。避免使用嵌套if-else语句,因为实现逻辑复杂,使得代码可读性较差。接下来要提到到的else-if语句可以很好的解决这个问题。

  • else-if语句
//判断a值是否在区间(10,20)func main() {    a := 15    if a > 20 {        fmt.Println("a大于20")    } else if a < 10 {        fmt.Println("a小于10")    } else {        fmt.Println("a小于20")        fmt.Println("a大于10")    }    fmt.Println("a的值为:", a)}/*a小于20a大于10a的值为: 15*/

else-if语句可以使用多个else-if关键字

func main() {    a := 13    if a > 20 {        fmt.Println("a大于20")    } else if a < 10 { //else-if语句后        fmt.Println("a小于10")    } else if a == 15 {        fmt.Println("a等于15")    } else {        fmt.Println("a小于20")        fmt.Println("a大于10")        fmt.Println("a不等于15")    }    fmt.Println("a的值为:", a)}/*a小于20a大于10a不等于15a的值为: 13*/

选择语句

switch语句

switch表示选择语句的关键字,根据初始化表达式得出一个值,然后根据case语句的条件,执行相应的代码块,最终返回特定内容。
如果没有遇到特定的case,则可以使用default case;如果已经遇到符合条件的case,那么后面的case都不会被执行。
在Go语言中,switch有两种类型

  • 表达式switch:case包含与switch表达式的值进行比较的表达式
  • 类型switch:case包含于特殊注释的switch表达式的类型进行比较的类型

表达式switch

func main() {    score := 90    level := "C"    switch score { //对应表达式的值选择case    case 90:        level = "A"    case 80:        level = "B"    case 70:        level = "C"    case 60:        level = "D"    default:        level = "NULL"    }    fmt.Printf("你的等级是%s\n", level)}

这种语句写法虽然简单,但是缺点也很明显,原因是它直能判断单值的case,对于除了固定的case以外的值,全都被返回到了default,使得输出数据变得不合理。例如,socre值为91,却打印出“你的等级是NULL”。

为了解决这一问题,我们可以使用完整的switch表达式,同时允许多个switch语句相互关联,比如下面的代码块,允许第二个switch语句接收第一个switch语句返回值作为选择条件。

func main() {    score := 90    level := "C"    switch score { //判断成绩所属区间    case 90:        level = "A"    case 80:        level = "B"    default:        level = "NULL"    }    switch { //可以接受上一个switch语句的case值,switch语句后的条件表达式不限制为常量或表达式,允许什么都不写    case level == "A":        fmt.Println("优秀") //单个case可以多个结果选项        fmt.Println("Good!")    case level == "B":        fmt.Println("良好")    default:        fmt.Println("你的成绩不存在!")    }    fmt.Println("你的成绩是:", score)}/*优秀Good!你的成绩是: 90 */

我们可以总结出Go语言的switch语句有以下特点:

  • switch后面的条件表达式可以为空、常量、整数
  • case表达式可以有多个
  • 左花括号必须同switch一行
  • 无需像C语言一样使用break关键字结束case(待补充)
  • 单个case值可以出现多个选择结果
  • 多个switch语句之间可以相互关联(允许接收前一个switch语句的返回结果)
  • fallthrough关键字可以把当前case控制权交给下一个case语句执行(不管什么条件都会被强制执行)
/*fallthrough写法*/func main() {    score := 80     level := "B"    switch score { //对应表达式的值选择case    case 90:        level = "A"    case 80:        level = "B"        fallthrough //把当前case控制权交给下一个语句判断,当前case语句被忽略    default:        level = "NULL"    }    fmt.Printf("你的等级是%s\n", level)}/*你的等级是NULL*/

以上语句score等于80,正常来看会选择对应case值80的选择语句,但是fallthrough关键字会忽略本层case语句的选择条件,强制执行下一个case语句的内容(不管什么条件都会被执行),所以输出的内容是default的选择语句。

type-switch语句

类型switch语句可以根据条件表达式的类型自动选择执行哪个case代码块。使用类型switch语句时,需要判断的变量必须是接口类型的变量。有关接口的知识点将在以后的学习补充和完善。
注意:type-switch语句不允许使用fallthrough

type Element interface{} //声明接口类型func main() {    var e Element = "这是一个字符串"    switch value := e.(type) { //根据类型选择对应case语句    case int:        fmt.Println("int", value)    case string:        fmt.Println("string", value)    default:        fmt.Println("unknown", value)    }}/*string 这是一个字符串*/

初始化switch

同样的,switch语句后面也可以写上初始化表达式,并且只能有一句语句

(待补充)

select语句

在选择语句中,除了switch语句,还有另一种select语句,这种语句用于配合通道(channel)的读写操作,用于多个channel的并发读写特性。有关并发的特性将在后面的学习中介绍。**switch语句是按顺序从上到下依次执行的,select语句是随机判断一个case来判断,直到匹配其中的一个case为止。

package mainimport (    "fmt")//并发编程的内容func main() {    a := make(chan int, 1024)    b := make(chan int, 1024)    for i := 0; i < 10; i++ {        fmt.Printf("第%d次", i)        a <- 1 //        b <- 1        select {        case <-a:            fmt.Println("from a")        case <-b:            fmt.Println("from b")        }    }}

循环语句

在Go语言中,循环语句的关键字是for,没有while关键字。for语句可以根据指定的条件重复执行其内部的代码块,这个判断条件一般是由for后面的子语句给出的。

for的子语句

for语句后面的三个子语句我们称为:初始化子语句条件子语句后置子语句,这三个子语句顺序不能颠倒,其中条件子语句是必需的,条件子语句会返回一个布尔型,true执行代码块,false则跳出循环。

func main() {    a := 0    b := 5    for a < b { //只有条件子语句,实际是 for ; a<b ; 的简写         a++        fmt.Println("a的值是:%d", a)    }}/*a的值是:%d 1a的值是:%d 2a的值是:%d 3a的值是:%d 4a的值是:%d 5*/

range子语句

每一个for语句都可以使用一个特殊的range子语句,其作用类似迭代器,用于轮询数组或者切片值的每一个元素,也可以用于轮询字符串的每一个字符串和字典值中的键值对,甚至还可以持续读取一个通道类型值中的元素

注意:range关键字左边表示是一对索引-值对

package mainimport (    "fmt")func main() {    str := "asdf"    for i, char := range str { //range关键字右边是range表达式,表达式一般写在for语句前面,提高代码可读性        fmt.Printf("这是第%d个字符串的值是:%d\n", i, char)    }    for _, char := range str {        fmt.Println(char) //使用空标识符_屏蔽索引值,只打印字符值    }    for i := range str {        fmt.Println(i) //使用空标识符_屏蔽字符值,只打印索引值    }    for range str {        fmt.Println("轮询完毕")    }}/*这是第0个字符串的值是:97这是第1个字符串的值是:115这是第2个字符串的值是:100这是第3个字符串的值是:102971151001020123轮询完毕轮询完毕轮询完毕轮询完毕*/

对于空字典或切片、空数组、空字符串等情况,for语句会直接结束,不会循环。

func main() {    str := "" //空字符串    for i, char := range str { //只有条件子语句        fmt.Printf("这是第%d个字符串的值是:%d\n", i, char)    }    for _, char := range str {        fmt.Println(char) //值对    }    for i := range str {        fmt.Println(i) //索引    }    for range str {        fmt.Println("轮询完毕")    }    fmt.Println("这是一个空字符串") //字符串为空,跳出for循环}/*这是一个空字符串*/

延迟语句

在Go语言中,除了上述提到的常规流程控制的语句之外,还有一些特殊的控制语句,也是Go语言的语法特性之一。defer语句就是其中一个,用于延迟调用指定函数,defer关键字只能出现在函数内部,并且只能用于调用外部函数。例如,如下的代码块,defer就是 fmt.Println 外部函数的延迟调用,被延迟的操作是defer后面的语句。

func main() {    defer fmt.Println("请延迟执行这条语句") //defer关键字只能出现于函数内部,并且用于外部函数的调用    fmt.Println("请先执行这条语句")}/*请先执行这条语句请延迟执行这条语句*/

defer 有两大特点:

  • 只有当defer语句全部执行完毕时,defer所在函数才算真正结束执行
  • 当函数中有defer语句时,需要等待所有defer语句执行完毕,才会执行return语句。

    /*利用defer特性打印反向数字列表*/var i int = 0func print(i int) { //构造打印函数    fmt.Println(i)}func main() {    for ; i < 5; i++ { //省略初始化子语句        defer print(i) //由于defer的延迟特性,满足先进后出,所以可将defer看成一个栈,依次打印出栈顺序    }}/*43210*/

    标签

    在Go语言中,还有一个特殊的概念那就是标签(类似汇编语言),可以给for、switch、select语句等流程控制代码块打上一个标签,配合标签标识符可以方便跳转到某一个地方继续执行,有助于提高编程效率。

    func main() {LOOP1: //标签    for i := 0; i < 5; i++ {        switch {        case i < 5:          fmt.Println("A")            break LOOP1 //跳到标签LOOP1,处于for循环以外,不再执行任务      case i == 5:            fmt.Println("B")      }        fmt.Println("i的值是:", i) //由于使用break跳转到标签LOOP1,此条语句不再执行  }}

A
*/

为了提高代码的可读性,建议标签名称使用大写字母和数字。标签可以标记任何语句,并不限定于流程控制语句,**未使用的标签会引发错误**。### break语句break语句用于打断当前流程控制,例如:

package main

import (

  "fmt"

)

func main() {

  for i := 0; i < 10; i++ {      fmt.Println("i的值是:", i)      if i > 4 {          break //打断,跳出当前for循环      }  }

}

/*
i的值是: 0
i的值是: 1
i的值是: 2
i的值是: 3
i的值是: 4
i的值是: 5
*/

对于嵌套流程控制语句,break只能中断当前循环,不能跳出外层循环。

package main

import (

  "fmt"

)

func main() {

  for i := 0; i < 5; i++ {      switch {      case i < 5:          fmt.Println("A")          break //跳出当前switch循环,未跳出外层for循环      case i == 5:          fmt.Println("B")      }      fmt.Println("i的值是:", i)  }

}

/*
A
i的值是: 0
A
i的值是: 1
A
i的值是: 2
A
i的值是: 3
A
i的值是: 4
*/

### continue语句与break语句相反,continue语句则用于跳转到指定代码块或标签位置**继续执行任务,且只能用于for循环**。

func main() {
LOOP1: //标签

  for i := 0; i < 5; i++ {      switch {      case i < 5:          fmt.Println("A")          continue LOOP1 //跳到标签LOOP1,处于for循环以外,继续执行任务      case i == 5:          fmt.Println("B")      }      fmt.Println("i的值是:", i) /  }

}

/*
A
A
A
A
A
*/

### goto语句goto语句用于**无条件跳转到相同函数的带标签语句,且只能在同一函数跳转**。

func main() {

  for i := 0; i < 3; i++ {      fmt.Println("A")      goto LOOP2       //跳到标签LOOP2      fmt.Println("B") //忽略不执行  LOOP2:      fmt.Println("i的值是:", i) //顺序执行  }

}

/*
A
i的值是: 0
A
i的值是: 1
A
i的值是: 2
*/


文章来源:智云一二三科技

文章标题:Golang 学习笔记:流程控制

文章地址:https://www.zhihuclub.com/2937.shtml

关于作者: 智云科技

热门文章

网站地图