Go 语言编程 — 逻辑控制语句

举报
云物互联 发表于 2021/08/06 00:17:14 2021/08/06
2.2k+ 0 0
【摘要】 目录 文章目录 目录条件判断if/else 语句switch 语句fallthrough 语句type-switch 语句 select(开关)语句 循环for 循环语句For-each range 循环语句 循环控制语句break 语句continue 语句goto 语句 条件判断 if/else 语句 示例: package...

目录

条件判断

在这里插入图片描述

if/else 语句

在这里插入图片描述
示例:

package main

import "fmt"

func main() { var a int = 100 if a > 0 && a < 20 { fmt.Printf("a 小于 20\n") } else { fmt.Printf("a 不小于 20\n") } fmt.Printf("a 的值为 : %d\n", a)
}

  
 

可见,Golang 中的条件表达式不需要使用 “()” 括起来。

另外,Golang 支持在判断时可以同时执行定义赋值等操作:

if err = af.Run(parenCtx, cfgPath); err != nil {
	log.Errf("AF finished with error: %v", err)
}

  
 

相当于先执行其他语句(通常是赋值语句),然后再执行条件判断语句。

注意:Golang 中 if 的条件判断语句是不可以仅仅编写赋值语句的:

if a = true {}

  
 

这样的代码在 C 语言中可以编译过,但 Golang 的编译器会报错。

switch 语句

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。

在这里插入图片描述

与 C 语言不同,Golang 中的 switch 匹配项后面也不需要再加 break 语句。switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case。如果我们需要执行后面的 case,可以使用 fallthrough 语句。

格式:

switch var1 { case val1: ... case val2: ... default: ...
}

  
 

其中,变量 var1 可以是任何类型,而 val1 和 val2 则是同类型的任意值,类型不被局限于常量或整数,但必须是相同的类型。或者最终结果为相同类型的表达式。如果希望通过布尔数据类型来进行判定,则 switch 关键字后不需要紧跟条件表达式。

同时,还可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3

示例:

package main

import "fmt"

func main() { var grade string var marks int = 90 /* 带有表达式的 switch 语句,表达式的结果与 case 进行匹配。 */ switch marks { case 90: grade = "A" case 80: grade = "B" case 50, 60, 70: grade = "C" default: grade = "D" } fmt.Printf("你的等级是 %s\n", grade); /* 不带有表达式的 switch 语句,由 case 语句表达式判断是否为 True。 */ switch { case grade == "A": fmt.Printf("优秀!\n") case grade == "B", grade == "C": fmt.Printf("良好\n") case grade == "D": fmt.Printf("及格\n") case grade == "F": fmt.Printf("不及格\n") default: fmt.Printf("差\n"); }
}

  
 

结果:

你的等级是 A
优秀!

  
 

fallthrough 语句

在 switch 中使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true,而是直接执行。

示例:

package main

import "fmt"

func main() { switch { case false: fmt.Println("1、case 条件语句为 false") fallthrough case true: fmt.Println("2、case 条件语句为 true") fallthrough case false: fmt.Println("3、case 条件语句为 false") fallthrough case true: fmt.Println("4、case 条件语句为 true") case false: fmt.Println("5、case 条件语句为 false") fallthrough default: fmt.Println("6、默认 case") }
}

  
 

结果:

2case 条件语句为 true
3case 条件语句为 false
4case 条件语句为 true

  
 

type-switch 语句

Golang 中,还可以使用 type-switch 来判断某个 interface(接口)变量中实际存储的变量类型。

格式:

switch x.(type) { case type: statements /* 可以定义任意个数的 case */ default: statements
}

  
 

示例:

package main

import "fmt"

func main() { /* 定义一个接口类型变量。 */ var itf interface{} /* 判断接口类型变量存储的数值的类型。 */ switch i := itf.(type) { case nil: fmt.Printf("interface 的类型: %T", i) case bool: fmt.Printf("interface 是 bool 型") case int: fmt.Printf("interface 是 int 型") case float64: fmt.Printf("interface 是 float64 型") case func(int) float64: fmt.Printf("interface 是 func(int) 型") default: fmt.Printf("未知类型") }
}

  
 

结果:

interface 的类型: <nil>

  
 

select(开关)语句

select 语句类似于用于通信的 switch 语句。区别在于 select 语句是专为 channel(通道)而设计的,每个 case 必须是一个通信操作,要么是发送(ch <- )要么是接收(<- ch)。

  • 每个 case 都必须是一个通信操作(communication clause)。
  • 所有 channel 表达式都会被求值。
  • 如果任意某个通信可以进行,它就执行,其他则被忽略。
  • 如果有多个 case 可以运行,select 会随机公平地选出一个执行。其他则被忽略。
  • 如果没有 case 可以运行:
    • 如果有 default 子句,则执行该语句。
    • 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Golang 不会重新对 channel 或值进行求值。

格式:

select { case communication clause: statements /* 你可以定义任意数量的 case */ default: statements
}

  
 

示例:

package main

import "fmt"
func main() { var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Println("received ", i1, " from c1") case c2<- i2: fmt.Println("sent ", i2, " to c2") case i3, ok := (<-c3): if ok { fmt.Println("received ", i3, " from c3") } else { fmt.Println("c3 is closed") } default: fmt.Println("no communication") }
}

  
 

因为 select 会循环检测所有 case 的表达式,所以 select 语句本身不需要表达式,这一点与 switch 语句也不通。select 语句中,如果有满足的 case 则执行并退出,否则一直循环检测。

package main

import ( "fmt" "time"
)

func test_channel(ch chan int, stop_ch chan bool) { var i int = 10 /* 每个 1s 向 ch 通道发送一次整型数据。 */ for j := 0; j < 10; j++ { ch<- i time.Sleep(time.Second) } stop_ch<- true
}

func main() { /* 初始化通道类型变量。 */ ch := make(chan int) stop_ch := make(chan bool) go test_channel(ch, stop_ch) for { select { /* 当 ch 通道接收到变量时,会随机选择 case a 或 b 执行。 */ case a := <-ch: fmt.Println("Recvice a: ", a) case b := <-ch: fmt.Println("Receive b: ", b) case _ = <-stop_ch: goto end } } end:
}

  
 

结果:

Receive b:  10
Recvice a:  10
Recvice a:  10
Recvice a:  10
Receive b:  10
Recvice a:  10
Receive b:  10
Receive b:  10
Recvice a:  10
Receive b:  10

  
 

注意:如果没有初始化 channel 类型变量就对其进行发送、接收操作的话,会触发错误:fatal error: all goroutines are asleep - deadlock。·

循环

for 循环语句

在这里插入图片描述

Golang 仅支持 for 循环,执行过程如下:

  1. 先对 init 赋初值;
  2. 判别 init 是否满足 condition 条件,若其值为真,则执行循环体内语句,然后执行 post。进入第二次循环,再判别 condition;
  3. 否则判断 condition 的值为假,不满足条件,就终止 for 循环,执行循环体外语句。

Golang 的 for 循环具有 3 种形式。

  1. 和 C 语言的 for 一样,但循环控制语句不需要使用 “()” 括起来:
for init; condition; post { }

  
 
  • init:一般为赋值表达式,给控制变量赋初值;
  • condition:关系表达式或逻辑表达式,循环控制条件;
  • post:一般为赋值表达式,给控制变量增量或减量。

示例:计算 1 到 10 的数字之和

package main

import "fmt"

func main() { sum := 0 for i := 0; i <= 10; i++ { sum += i } fmt.Println(sum)
}

  
 
  1. 和 C 语言的 while 循环一样,省略了 init 和 post:
for condition { }

  
 

示例:

package main

import "fmt"

func main() { sum := 1 for sum <= 10 { sum += sum } fmt.Println(sum)
}

  
 
  1. 和 C 的 for (;;) 一样,省略 init、condition 和 post,执行无限循环:
for {}

  
 

示例:

package main

import "fmt"

func main() { sum := 0 for { sum++ // 无限循环下去 } fmt.Println(sum)
}

  
 

For-each range 循环语句

Golang 提供了 range(范围)关键字,用于 for 循环中迭代字符串(String)、数组(Array)、切片(Slice)、通道(Channel)或集合(Map)数据类型变量中所含有的元素。

  • 字符串、数组、切片:迭代元素的索引和索引对应的值。与 Python 中的 enumerate() 函数类似。
  • 集合:迭代 key/value 对。与 Python 中的 Dict.items() 成员方法类似。
  • 通道:迭代通道接收的数据。

格式:

for key, value := range oldMap { newMap[key] = value
}

  
 

示例:

package main

import "fmt"

func main() { /* 定义字符串数组变量 */ arr := []string {"hello", "world"} for idx, str := range arr { fmt.Println(idx, str) } /* 定义数字数组变量 */ numbers := [6]int {1, 2, 3, 5} for idx, num := range numbers { fmt.Printf("第 %d 位 x 的值 = %d\n", idx, num) }  
}

  
 

结果:

0 hello
1 world
第 0 位 x 的值 = 11 位 x 的值 = 22 位 x 的值 = 33 位 x 的值 = 54 位 x 的值 = 05 位 x 的值 = 0

  
 

示例:

package main

import "fmt"

func main() { /* 定义 Map 类型变量。 */ kvs := map[string]string {"a": "apple", "b": "banana"} for k, v := range kvs { fmt.Printf("%s: %s\n", k, v) } /* 迭代字符串时,第一个参数是字符的索引,第二个是字符的 rune(字符的字节编码)数值。 */ for i, c := range "go" { fmt.Println(i, c) }
}

  
 

结果:

a: apple
b: banana
0 103
1 111

  
 

循环控制语句

break 语句

在这里插入图片描述

  1. 用于循环语句中跳出循环,并开始执行循环之后的语句。
  2. break 在 switch 语句中在执行一条 case 后跳出。
  3. 在多重循环中,可以用标号 label 标出想跳出的循环。

示例:

package main

import "fmt"

func main() { // 不使用 label 标记 fmt.Println("---- break ----") for i := 1; i <= 3; i++ { fmt.Printf("i: %d\n", i) for i2 := 11; i2 <= 13; i2++ { fmt.Printf("i2: %d\n", i2) break } } // 使用 label 标记,常见于跳出嵌套循环。 fmt.Println("---- break label ----") re: for i := 1; i <= 3; i++ { fmt.Printf("i: %d\n", i) for i2 := 11; i2 <= 13; i2++ { fmt.Printf("i2: %d\n", i2) break re } }
}

  
 

结果:

---- break ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
---- break label ----
i: 1
i2: 11

  
 

continue 语句

在这里插入图片描述

与 breck 不同,continue 不是跳出循环,而是跳过当前循环并执行下一次循环。所以,在 for 循环中,执行 continue 语句同样会触发 for 增量语句的执行。

在多重循环中,同样可以用标号 label 标出想 continue 的循环。

示例:

package main

import "fmt"

func main() { // 不使用 label 标记 fmt.Println("---- continue ---- ") for i := 1; i <= 3; i++ { fmt.Printf("i: %d\n", i) for i2 := 11; i2 <= 13; i2++ { fmt.Printf("i2: %d\n", i2) continue } } // 使用标记 fmt.Println("---- continue label ----") re: for i := 1; i <= 3; i++ { fmt.Printf("i: %d\n", i) for i2 := 11; i2 <= 13; i2++ { fmt.Printf("i2: %d\n", i2) continue re } }
}

  
 

结果:

---- continue ----
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
---- continue label ----
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11

  
 

goto 语句

在这里插入图片描述

与 C 语言类似的,goto 语句可以无条件地转移到过程中指定的行。goto 语句通常与条件语句配合使用。可用来实现条件转移,构成循环,跳出循环体等功能。

通常的,在结构化程序设计中一般不主张使用 goto 语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。

格式:

goto label;
...

label: statements;

  
 

示例:在变量 a 等于 15 的时候跳过本次循环并回到循环的开始语句 LOOP 处

package main

import "fmt"

func main() { /* 定义局部变量 */ var a int = 10 /* 循环 */ LOOP: for a < 20 { if a == 15 { /* 跳过迭代 */ a = a + 1 goto LOOP } fmt.Printf("a 的值为 : %d\n", a) a++ }  
}

  
 

文章来源: is-cloud.blog.csdn.net,作者:范桂飓,版权归原作者所有,如需转载,请联系作者。

原文链接:is-cloud.blog.csdn.net/article/details/107139623

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。