0


Go之流程控制大全: 细节、示例与最佳实践

本文深入探讨Go语言中的流程控制语法,包括基本的

if-else

条件分支、

for

循环、

switch-case

多条件分支,以及与特定数据类型相关的流程控制,如

for-range

循环和

type-switch

。文章还详细描述了

goto

fallthrough

等跳转语句的使用方法,通过清晰的代码示例为读者提供了直观的指导。

关注【TechLead KrisChang】,分享互联网架构、云服务技术、AI技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。

file

引言

在计算机编程中,流程控制是核心的组成部分,它决定了程序应该如何根据给定的情况执行或决策。以下是Go语言所支持的流程控制结构的简要概览:
流程控制类型代码if-else条件分支

if condition { } else { }

for循环

for initialization; condition; post { }

switch-case多条件分支

switch value { case v1: ... default: ... }

容器类型的for-range循环

for key, value := range container { }

接口类型的type-switch多条件分支

switch v := value.(type) { case T: ... }

通道类型的select-case多分支

select { case <-ch: ... default: ... }

break跳转语句

break

continue跳转语句

continue

goto跳转语句

goto label

fallthrough跳转语句

fallthrough

在后续部分,我们将深入探讨每种流程控制结构的细节和应用案例,帮助你更好地理解和掌握Go语言的流程控制工具。


if-else条件分支

在Go中,

if-else

结构提供了条件判断的基本方式。与许多其他编程语言类似,它的基本语法包括测试一个条件,并根据该条件的真假来执行相应的代码块。

基础用法

流程控制类型代码if

if condition { }

if-else

if condition { } else { }

if-else if-else

if condition1 { } else if condition2 { } else { }
示例与说明
  1. ifx :=10if x >5{ fmt.Println("x is greater than 5")}当条件 x > 5 成立时,代码会输出 “x is greater than 5”。
  2. if-elsex :=3if x >5{ fmt.Println("x is greater than 5")}else{ fmt.Println("x is not greater than 5")}因为 x > 5 的条件不成立,所以代码会输出 “x is not greater than 5”。
  3. if-else if-elsex :=5if x >10{ fmt.Println("x is greater than 10")}elseif x <5{ fmt.Println("x is less than 5")}else{ fmt.Println("x is 5")}在这个示例中,由于 x 等于 5,代码会输出 “x is 5”。

带初始化语句的if条件分支

在Go中,

if

语句可以包含一个初始化语句,通常用于定义在条件测试中使用的临时变量。
流程控制类型代码if with initialization

if stmt; condition { }
示例与说明
if y :=computeValue(); y >10{
    fmt.Println("y is greater than 10")}else{
    fmt.Println("y is not greater than 10")}

在这个示例中,我们首先调用 computeValue() 函数(假设它返回一个整数)并将结果赋值给变量 y。然后我们根据 y > 10 的条件来决定输出什么。这种结构允许我们在一个简洁的语句中完成初始化和条件测试。

for循环

for

循环是Go语言中的唯一循环结构,但其灵活性足以覆盖其他编程语言中的多种循环结构。通过不同的组合,Go的

for

循环可以模拟传统的

while

do-while

循环。

基础用法

流程控制类型代码Basic loop

for initialization; condition; post { }

While-like loop

for condition { }

Infinite loop

for { }
示例与说明
  1. Basic loopfor i :=0; i <5; i++{ fmt.Println(i)}这是最常见的for循环形式,上述代码会输出0到4。
  2. While-like loopx :=5for x >0{ fmt.Println(x) x--}这种结构模拟了传统的while循环。上述代码会输出从5到1的数字。
  3. Infinite loopfor{ fmt.Println("This will run indefinitely!")}除非有break或其他控制语句,否则这种循环会无限运行。在某些情况下,这可以用于持续等待外部输入或其他中断。

range

的for循环

Go语言提供了

for-range

结构,用于迭代数组、切片、字符串或映射的元素。
流程控制类型代码Range loop

for key, value := range container { }
示例与说明
nums :=[]int{1,2,3,4,5}for idx, num :=range nums {
    fmt.Printf("Index: %d, Value: %d\n", idx, num)}

这个示例中,for-range循环迭代了一个整数切片,并输出每个元素及其索引。同样地,for-range可以用于迭代其他容器类型。


switch-case多条件分支

在Go语言中,

switch-case

结构提供了一个清晰的方式来进行多条件判断。与其他语言的

switch

结构略有不同,Go的

switch

更加灵活,不仅可以用于常量和整数值,还可以用于更复杂的条件判断。

基础用法

流程控制类型代码Basic switch

switch expression { case value1: ... default: ... }

Multiple values

switch expression { case val1, val2: ... }

No expression

switch { case condition1: ... }
示例与说明
  1. Basic switchfruit :="apple"switch fruit {case"banana": fmt.Println("This is a banana.")case"apple": fmt.Println("This is an apple.")default: fmt.Println("Unknown fruit.")}上述代码会输出 “This is an apple.”,因为 fruit 的值是 “apple”。
  2. Multiple valuesday :=2switch day {case1,7: fmt.Println("Weekend")case2,3,4,5,6: fmt.Println("Weekday")default: fmt.Println("Invalid day")}这个示例中,我们检查 day 是否是工作日还是周末。上述代码会输出 “Weekday”。
  3. No expressionx :=10switch{case x >5: fmt.Println("x is greater than 5")case x <5: fmt.Println("x is less than 5")default: fmt.Println("x is 5")}在这种形式中,switch没有伴随的表达式,它仅仅评估case后的条件。上述代码会输出 “x is greater than 5”。

fallthrough

关键字

在Go中,

switch

case

默认不会"贯穿"(即一旦匹配到一个

case

,它就会退出

switch

,不会执行后续的

case

)。如果你想继续执行下一个

case

,你需要使用

fallthrough

关键字。
流程控制类型代码Using fallthrough

case value: ... fallthrough ...
示例与说明
value :=5switch value {case5:
    fmt.Println("Value is 5")fallthroughcase6:
    fmt.Println("Value is 6 or it fallthrough from 5")default:
    fmt.Println("Another value")}

上述代码会连续输出 “Value is 5” 和 “Value is 6 or it fallthrough from 5”,因为fallthrough使得程序继续执行下一个case。


容器类型的for-range循环

在Go中,

for-range

结构是处理容器类型(如数组、切片、字符串和映射)的强大工具。它可以非常方便地遍历容器中的所有元素,无需手动处理索引或键。

数组和切片

流程控制类型代码遍历数组或切片

for idx, value := range arrayOrSlice { }
示例与说明
nums :=[]int{1,2,3,4,5}for idx, num :=range nums {
    fmt.Printf("Index: %d, Value: %d\n", idx, num)}

此代码遍历nums切片的每一个元素,输出其索引和值。
file

示例与说明

str :="hello"for idx, char :=range str {
    fmt.Printf("Index: %d, Char: %c\n", idx, char)}

此代码遍历str字符串中的每个字符,并输出其索引和字符值。

file

m :=map[string]int{"a":1,"b":2,"c":3}for key, value :=range m {
    fmt.Printf("Key: %s, Value: %d\n", key, value)}

此代码遍历映射m中的每个键值对,输出其键和值。
总的来说,for-range结构为Go程序员提供了一个简单而强大的方式来遍历和操作容器类型的数据。通过简洁的语法,我们可以有效地处理各种容器,而无需担心复杂的索引和边界条件。

接口类型的type-switch多条件分支

在Go语言中,接口类型允许我们处理多种不同的数据类型,但有时我们需要知道接口变量的具体类型。这时,

type-switch

结构提供了一种优雅的方式来进行类型判断和分支处理。

基础用法

流程控制类型代码type-switch

switch v := i.(type) { case T: ... default: ... }
示例与说明
  1. 基础type-switchvar i interface{}="hello"switch v := i.(type){caseint: fmt.Printf("It's an int with value %d\n", v)casestring: fmt.Printf("It's a string with value %s\n", v)default: fmt.Printf("Unknown type: %T\n", v)}此代码首先声明了一个接口类型的变量i并赋值为字符串"hello"。然后,使用type-switch来检查i的动态类型。上述代码将输出:“It’s a string with value hello”。

type-switch

中的其他用法

type-switch

不仅限于基本类型,还可以用于自定义类型、结构体等。
流程控制类型代码自定义类型

case CustomType: ...

结构体

case structType: ...
示例与说明
  1. 自定义类型和结构体type MyString stringtype MyStruct struct{ Field int}var i interface{}=MyString("hello")switch v := i.(type){case MyString: fmt.Printf("It's a MyString with value %s\n",string(v))case MyStruct: fmt.Printf("It's a MyStruct with field value %d\n", v.Field)default: fmt.Printf("Unknown type: %T\n", v)}在这个示例中,我们定义了一个自定义类型MyString和一个结构体MyStruct。然后,我们再次使用type-switch来检查接口变量i的类型。给定的代码将输出:“It’s a MyString with value hello”。

总的来说,

type-switch

结构为Go开发人员提供了一种清晰、简洁的方式来判断接口变量的动态类型,并进行分支处理。掌握这一结构对于在Go中正确处理接口和多态性至关重要。


通道类型的select-case多分支

Go语言中的

select

关键字是用于处理多个通道的读/写操作。当我们需要同时从多个通道接收或向多个通道发送数据时,

select

结构提供了一种方式来处理这些操作,使我们可以在一个通道准备好时执行相应的操作。

基础用法

流程控制类型代码select-case

select { case operation1: ... case operation2: ... }
示例与说明
  1. 基础select-casech1 :=make(chanint,1)ch2 :=make(chanstring,1)ch1 <-1ch2 <-"hello"select{case i :=<-ch1: fmt.Printf("Received from ch1: %d\n", i)case s :=<-ch2: fmt.Printf("Received from ch2: %s\n", s)default: fmt.Println("No data received")}这段代码定义了两个通道,分别发送一个整数和一个字符串。使用select结构,程序尝试从ch1ch2中接收数据。此代码可能会输出ch1ch2的数据,因为select会随机选择一个可用的case执行。

使用

default

select

结构中,可以使用

default

语句来处理当所有通道都不可用时的情况。

示例与说明
  1. 使用defaultch :=make(chanint,1)select{case i :=<-ch: fmt.Printf("Received from ch: %d\n", i)default: fmt.Println("No data available")}在这个例子中,我们尝试从通道ch中接收数据。但由于没有数据发送到该通道,程序将输出"No data available"。

使用

select

进行超时处理

利用

select

结构,我们还可以轻松实现超时机制。

示例与说明
  1. 超时处理ch :=make(chanint,1)gofunc(){ time.Sleep(2* time.Second) ch <-1}()select{case i :=<-ch: fmt.Printf("Received from ch: %d\n", i)case<-time.After(1* time.Second): fmt.Println("Timeout!")}这段代码中,我们试图从通道ch中接收数据,但我们只等待1秒。使用time.After函数,我们可以轻松实现超时逻辑。如果1秒内没有从ch中接收到数据,程序将输出"Timeout!"。

总之,

select-case

结构为Go开发人员处理多个通道提供了一种非常方便的方式。它不仅允许我们并发地处理多个通道,还可以轻松实现超时和默认操作,使并发编程变得简单而强大。


break跳转语句

在Go语言中,

break

语句主要用于提前结束一个循环或

switch

select

等代码块的执行。它使我们可以在满足特定条件时跳出当前执行的代码块。

基础用法

流程控制类型代码break

break
示例与说明
  1. 在for循环中使用breakfor i :=0; i <10; i++{if i ==5{break} fmt.Println(i)}这段代码将打印从0到4的数字。当i等于5时,break语句会被触发,从而提前结束循环。
  2. 在switch中使用breakswitch2{case1: fmt.Println("Case 1")case2: fmt.Println("Case 2")iftrue{break} fmt.Println("This won't be printed")case3: fmt.Println("Case 3")}在此示例中,当匹配到case 2时,程序会输出"Case 2",然后由于break语句,fmt.Println("This won't be printed")将不会被执行。

带标签的break

在Go中,你还可以使用带标签的

break

语句来跳出外层循环或其他代码块。

示例与说明
  1. 使用带标签的breakouterLoop:for i :=0; i <5; i++{for j :=0; j <5; j++{if i*j ==6{break outerLoop } fmt.Println(i, j)}}在上述代码中,我们有两个嵌套的for循环。当i*j等于6时,带标签的break语句会被触发,这将导致外层的for循环提前结束。

总体上说,

break

语句在Go中提供了一种灵活的方式来控制代码块的执行流程。它在循环、

switch

select

等结构中都有着广泛的应用,使我们可以根据特定的条件提前结束代码块的执行。


continue跳转语句

在Go语言中,

continue

语句被用于跳过当前循环的剩余语句,并开始下一次循环。不同于

break

语句,它并不会结束整个循环,而只是跳过当前的迭代。

基础用法

流程控制类型代码continue

continue
示例与说明
  1. 在for循环中使用continuefor i :=0; i <10; i++{if i%2==0{continue} fmt.Println(i)}上述代码将打印出0到9之间的所有奇数。当i是偶数时,continue语句会被触发,从而跳过当前循环的剩余部分。
  2. 在for-range循环中使用continuearr :=[]int{1,2,3,4,5}for idx, val :=range arr {if val ==3{continue} fmt.Printf("arr[%d] = %d\n", idx, val)}这段代码遍历一个整数切片,并打印除3之外的所有元素的索引和值。当元素值为3时,continue语句会被触发,从而跳过当前迭代。

带标签的continue

break

语句类似,

continue

也支持带标签的形式,从而可以在多层嵌套的循环中指定跳转到哪个外层循环的下一次迭代。

示例与说明
  1. 使用带标签的continueouterLoop:for i :=0; i <3; i++{for j :=0; j <3; j++{if i ==1&& j ==1{continue outerLoop } fmt.Println(i, j)}}在这个例子中,我们有两个嵌套的for循环。当i等于1并且j等于1时,带标签的continue语句会被触发,这会导致直接跳到外层循环的下一次迭代,而内层循环的剩余迭代会被跳过。

总之,

continue

语句为Go开发人员提供了一种方式,可以在满足特定条件时跳过循环的某次迭代。这使得我们可以更灵活地控制循环的执行流程。


goto跳转语句

在Go语言中,

goto

语句允许程序在执行时跳转到指定的标签。尽管

goto

语句在现代编程中不那么常用,并且在某些情况下可能引发困惑或使代码难以阅读,但在某些特定场景中,它可能是有用的。

基础用法

流程控制类型代码goto

goto
示例与说明
  1. 简单的goto使用funcmain(){ fmt.Println("Start")goto end fmt.Println("This won't be printed")end: fmt.Println("End")}在此示例中,程序首先打印"Start",然后跳转到end标签,继续执行下面的代码。因此,fmt.Println("This won't be printed") 不会被执行。
  2. 使用goto进行错误处理funcdivide(x, y int)(int,error){if y ==0{return0, errors.New("Cannot divide by zero")}return x / y,nil}funcmain(){ result, err :=divide(10,0)if err !=nil{goto handleErr } fmt.Println("Result:", result)returnhandleErr: fmt.Println("Error:", err)}在这个例子中,我们使用goto语句来跳转到错误处理部分。这种做法在某些情况下可以使错误处理更为集中。

尽管

goto

语句在Go中是可用的,但开发者通常建议在只有真正需要的情况下使用它,因为不当的使用可能导致代码难以理解和维护。当您可以使用其他结构(如

if

for

switch

)来实现相同的结果时,最好避免使用

goto


fallthrough跳转语句

在Go的

switch

语句中,一旦某个

case

匹配成功,后续的

case

将不会再被检查或执行。然而,Go提供了一个特有的关键字:

fallthrough

,它可以强制执行紧跟它后面的

case

,无论该

case

是否匹配。

基础用法

流程控制类型代码fallthrough

fallthrough
示例与说明
  1. 基础的fallthrough使用x :=10switch x {case10: fmt.Println("x is 10")fallthroughcase20: fmt.Println("x is 20")default: fmt.Println("x is neither 10 nor 20")}在此示例中,x的值是10,所以程序会首先打印"x is 10"。由于第一个case后面有fallthrough语句,程序继续执行下一个case,即使x的值并不是20,所以还会打印"x is 20"。
  2. fallthrough在非连续case中的使用y :="apple"switch y {case"banana": fmt.Println("y is banana")case"apple": fmt.Println("y is apple")fallthroughcase"orange": fmt.Println("y is orange")default: fmt.Println("y is neither banana, apple, nor orange")}在这个例子中,当y的值为"apple"时,会打印"y is apple"。然后,由于存在fallthrough语句,“y is orange"也会被打印,即使y的值并不是"orange”。

需要注意的是,虽然

fallthrough

提供了一种特殊的控制流,但在大多数场景中,过度或不恰当的使用可能导致代码难以阅读和理解。因此,推荐在真正需要时才使用它,并确保代码的意图清晰可见。


关注【TechLead KrisChang】,分享互联网架构、云服务技术、AI技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。


本文转载自: https://blog.csdn.net/magicyangjay111/article/details/135975103
版权归原作者 TechLead KrisChang 所有, 如有侵权,请联系我们删除。

“Go之流程控制大全: 细节、示例与最佳实践”的评论:

还没有评论