写点什么

巨细靡遗流程控制,Go lang1.18 入门精炼教程,由白丁入鸿儒,Go lang 流程结构详解 EP09

  • 2022 年 8 月 12 日
    北京
  • 本文字数:3680 字

    阅读完需:约 12 分钟

巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09

流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序。众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang 程序的流程控制结构一共有三种:顺序结构,选择结构,循环结构。顺序结构:从上向下,逐行执行;选择结构:条件满足,某些代码才会执行,0-1 次;循环结构:条件满足,某些代码会被反复的执行多次,0-N 次

选择结构之条件判断 if/else

市面上的语言都有 if/else 逻辑,逻辑非常简单,只要满足条件,就会执行条件代码块的逻辑:


if 布尔表达式 {     /* 在布尔表达式为 true 时执行 */  }    if 布尔表达式 {     /* 在布尔表达式为 true 时执行 */  } else {    /* 在布尔表达式为 false 时执行 */  }    if 布尔表达式1 {     /* 在布尔表达式1为 true 时执行 */  } else if 布尔表达式2{     /* 在布尔表达式1为 false ,布尔表达式2为true时执行 */  } else{     /* 在上面两个布尔表达式都为false时,执行*/  }
复制代码


具体逻辑:


package main    import "fmt"    func main() {      var a int = 1      /* 使用 if 语句判断布尔表达式 */    if a < 20 {      /* 如果条件为 true 则执行以下语句 */      fmt.Printf("a 小于 20\n")    }    fmt.Printf("a 的值为 : %d\n", a)  }
复制代码


程序返回:


a 小于 20  a 的值为 : 1
复制代码


需要注意的是,条件变量类型要一致才能比较。


除此之外,if 还可以在判断之前执行逻辑:


package main    import (    "fmt"  )    func main() {    if num := 10; num%2 == 0 { //checks if number is even      fmt.Println(num, "is even")    } else {      fmt.Println(num, "is odd")    }  } 
复制代码


程序返回:


10 is even
复制代码


也就是说,当判断变量 num 对 2 取余是否等于 0 之前,我们可以先给 num 进行赋值操作。


同时 if/else 也支持多分支判断:




package main import ( "fmt" ) func main() { score := 88 if score >= 90 { fmt.Println("成绩等级为A") } else if score >= 80 { fmt.Println("成绩等级为B") } else if score >= 70 { fmt.Println("成绩等级为C") } else if score >= 60 { fmt.Println("成绩等级为D") } else { fmt.Println("成绩等级为E 成绩不及格") } }
复制代码


程序返回:


成绩等级为B
复制代码


这里程序根据变量的值而选择执行不同的分支代码,但需要注意的是,Go lang 对于 { 和 } 的位置有严格的要求,它要求 else if (或 else ) 和两边的花括号,必须在同一行。即使在 { 和 } 之间只有一条语句,这两个花括号也是不能省略的。

选择结构之选择判断 switch

switch 关键字是一个条件语句,它计算表达式并将其与可能匹配的列表进行比较,并根据匹配执行代码块。它可以被理解为用一种普适的方式来写多个 if else 判断子句。


switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。 switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。


说白了就是,每一个 case 都默认自动 break,执行完了一个,switch 逻辑也就结束了,不会顺序执行别的 case,但是可以使用 fallthrough 强制执行后面的 case 代码:




package main import "fmt" func main() { /* 定义局部变量 */ var grade string = "B" var marks int = 40 switch marks { case 90: grade = "A" case 80: grade = "B" case 50, 60, 70: grade = "C" //case 后可以由多个数值 default: grade = "D" } switch { case grade == "A": fmt.Printf("A\n") case grade == "B", grade == "C": fmt.Printf("B\n") case grade == "D": fmt.Printf("D\n") case grade == "F": fmt.Printf("F\n") default: fmt.Printf("low\n") } fmt.Printf("你的等级是 %s\n", grade) }
复制代码


程序返回:


D  你的等级是 D
复制代码


这里我们先通过 switch 对 marks 变量进行值判断,在 case 分支里赋值 grade 变量,随后又在 switch 逻辑中对 grade 做恒等判断,然后输出。


假设需要贯通后续的 case,就添加 fallthrough 关键字:


package main    import (    "fmt"  )    func main() {    switch x := 5; x {    default:      fmt.Println(x)    case 5:      x += 10      fmt.Println(x)      fallthrough    case 6:      x += 20      fmt.Println(x)      }    }
复制代码


这里首先进入 case5 逻辑,x 经过运算后变为 15,随后贯通进入下一个逻辑,x += 20 逻辑,变为 35。


程序返回:


15  35
复制代码


需要注意的是,fallthrough 应该是某个 case 的最后一行。如果它出现在中间的某个地方,编译器就会抛出错误。

循环结构之遍历 for

for 关键字可以用来重复执行某一段代码,在 Python 中,遍历方式有三种:for 、 while 和 do while 。但是 Go lang 只为我们提供了一种:for:


package main    import (    "fmt"  )    func main() {    num := 1    for num < 3 {      fmt.Println(num)      num++    }    }
复制代码


程序返回:


1  2
复制代码


这里是但条件循环,如果满足条件,for 代码块的逻辑会重置执行。


我们还可以为遍历添加额外的表达式逻辑,比如初始化控制变量,在整个循环生命周期内,只执行一次;设置循环控制条件,该表达式值为 true 时循环,值为 false 时结束循环;每次循环完都会执行此表达式,可以利用其让控制变量增量或减量:


package main    import (    "fmt"  )    func main() {    for num := 0; num < 4; num++ {      fmt.Println(num)    }    }
复制代码


程序返回:


0  1  2  3
复制代码


需要注意的是,在 for 关键字中声明的变量,也只在 for 的代码块中有效,因为和 Python 不同,go lang 有严格的块作用域限制。


在 Go lang 中遍历一个可迭代的对象一般使用 for-range 语句实现,其中 range 后面可以接数组、切片、字符串等, range 会返回两个值,第一个是索引值,第二个是数据值:


package main    import (    "fmt"  )    func main() {      str := "123456789"    for index, value := range str {      fmt.Printf("index %d, value %c\n", index, value)    }    }
复制代码


程序返回:


index 0, value 1  index 1, value 2  index 2, value 3  index 3, value 4  index 4, value 5  index 5, value 6  index 6, value 7  index 7, value 8  index 8, value 9
复制代码


如果 for 关键字后面没有表单式,就是死循环:


package main    import (    "fmt"  )    func main() {      num := 1      for {        fmt.Println(num)      num++        if num > 3 {        break      }      }    }
复制代码


程序返回:


1  2  3
复制代码


是的,我们当然可以使用 break 关键字来中断循环。


但需要注意的是,break 只能终端当前循环,不能终端外部循环:


package main    import "fmt"    func main() {    /* 定义局部变量 */    var i, j int    for i = 2; i < 10; i++ {      for j = 2; j <= (i / j); j++ {        if i%j == 0 {          break // 如果发现因子,则不是素数        }      }      if j > (i / j) {        fmt.Printf("%d  是素数\n", i)      }    }  }
复制代码


程序返回:


2  是素数  3  是素数  5  是素数  7  是素数
复制代码


和 Python 一样,Go lang 也具备 continue 关键字,continue 语句用来跳出 for 循环中的当前循环:


package main    import "fmt"    func main() {      for num := 1; num <= 10; num++ {      if num%2 == 0 {        continue      }      fmt.Println(num)    }    }
复制代码


程序返回:


1  3  5  7  9
复制代码


在 continue 语句后的所有的 for 循环语句都不会在本次循环中执行,执行完 continue 语句后将会继续执行一下次循环。这样我们就可以跳过偶数,直接打印出 10 以内的奇数。

goto 无条件跳转

使用 goto 关键字可以直接跳到下一步要执行的标签代码:


package main    import "fmt"    func main() {      for x := 0; x < 10; x++ {        for y := 0; y < 10; y++ {          if y == 2 {          // 跳转到标签          goto breakHere        }        }    }      // 手动返回, 避免执行进入标签    return      // 标签  breakHere:    fmt.Println("done")  }
复制代码


程序返回:


done
复制代码


需要注意的是,goto 关键字与标签之间不能有变量声明,否则编译错误。

结语

和 Python 和 Ruby 相比,整体上,在流程结构控制环节,Go lang 表现出了极大的克制,语法上删繁就简, 把动态语言那些桀骜不驯的语法糖压制成行文工整的诗,这样的好处是对初学者极为友好,没有太多规范需要记忆,大道至简,大巧不工。我们可以吐槽它没有 while 或者是 do while,亦或者是 lambda 表达式等可以炫技的资本,但,那又如何呢?就像乔帮主在聚贤庄力战群雄,大杀四方,所倚重的不过是一套普普通通的太祖长拳,Go lang 亦如此,务实胜过炫技,简单未必普通。

发布于: 刚刚阅读数: 4
用户头像

专注技术,凝聚意志,解决问题 v3u.cn 2020.12.21 加入

还未添加个人简介

评论

发布
暂无评论
巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09_Go_刘悦的技术博客_InfoQ写作社区