这里有新鲜出炉的 GO 语言教程,程序狗速度看过来!
Go 是一种新的语言,一种并发的、带垃圾回收的、快速编译的语言。Go 是谷歌 2009 年发布的第二款编程语言。2009 年 7 月份,谷歌曾发布了 Simple 语言,它是用来开发 Android 应用的一种 BASIC 语言。
这篇文章主要给大家介绍了关于 Golang 中 switch 和 select 的用法教程,文中通过示例代码将 switch 语句与 select 语句的使用方法介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
本文主要给大家介绍了关于 Golang 中 switch 和 select 用法的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:
一、switch 语句
switch 语句提供了一个多分支条件执行的方法。每一个 case 可以携带一个表达式或一个类型说明符。前者又可被简称为 case 表达式。因此,Go 语言的 switch 语句又分为表达式 switch 语句和类型 switch 语句。
1、表达式 switch 语句
- var name string
- ...
- switch name {
- case "Golang":
- fmt.Println("Golang")
- case "Rust":
- fmt.Println("Rust")
- default:
- fmt.Println("PHP是世界上最好的语言")
- }
Go 会依照从上至下的顺序对每一条 case 语句中 case 表达式进行求值,只要被发现其表达式与 switch 表达式的结果相同,该 case 语句就会被选中。其余的 case 语句会被忽略。 与 if 相同,switch 语句还可以包含初始化字句,且其出现位置和写法如出一辙:
- names := []string{"Golang","java","PHP"}
- switch name:=names[0];name {
- case "Golang":
- fmt.Println("Golang")
- ...
- default:
- fmt.Println("Unknown")
- }
2、类型 switch 语句
类型 switch 语句与一般形式有两点差别。第一点,紧随 case 关键字的不是表达式,而是类型说明符。类型说明符由若干个类型字面量组成,且多个类型字面量之间由英文逗号分隔。第二点,它的 switch 表达式是非常特殊的。这种特殊的表达式也起到了类型断言的作用,但其表现形式很特殊,如:
, 其中 v 必须代表一个接口类型的值。该类表达式只能出现在类型 switch 语句中,且只能充当 switch 表达式。一个类型 switch 语句的示例如下:
- v.(type)
- v := 11
- switch i := interface{}(v).(type) {
- case int, int8, int16, int32, int64:
- fmt.Println("A signed integer:%d. The type is %T. \n", v, i)
- case uint, uint8, uint16, uint32, uint64:
- fmt.Println("A unsigned integer: %d. The type is %T. \n", v, i)
- default:
- fmt.Println("Unknown!")
- }
我们这里把 switch 表达式的结果赋给了一个变量。如此以来,我们就可以在该 switch 语句中使用这个结果了。这段代码被执行后, 输出:"
"
- A signed integer:11. The type is int.
最后说一下 fallthrough。它既是一个关键字,又可以代表一条语句。fallthrough 语句可被包含在表达式 switch 语句中的 case 语句中。它的作用是使控制权流转到下一个 case。不过要注意 fallthrough 语句仅能作为 case 语句中的最后一条语句出现。并且,包含它的 case 语句不是其所属 switch 语句的最后一条 case 语句。
二、select 语句
golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。
示例:
- ch1 := make (chan int, 1)
- ch2 := make (chan int, 1)
- ...
- select {
- case <-ch1:
- fmt.Println("ch1 pop one element")
- case <-ch2:
- fmt.Println("ch2 pop one element")
- }
注意到 select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是【IO 操作】 。
此示例里面 select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据。 则 select 语句结束。
break 语句也可以被包含在 select 语句中的 case 语句中。它的作用是立即结束当前的 select 语句的执行。不论其所属的 case 语句中是否还有未被执行的语句。
【使用 select 实现 timeout 机制】
如下:
- timeout := make(chan bool, 1)
- go func() {
- time.Sleep(time.Second * 10)
- timeout <- true
- }()
- select {
- case <-pssScanResponseChan:
- case <-timeout:
- fmt.PrintIn("timeout!")
- }
当超时时间到的时候,case2 会操作成功。 所以 select 语句则会退出。 而不是一直阻塞在 ch 的读取操作上。 从而实现了对 ch 读取操作的超时设置。
下面这个更有意思一点。
当 select 语句带有 default 的时候:
- ch1 := make (chan int, 1)
- ch2 := make (chan int, 1)
- select {
- case <-ch1:
- fmt.Println("ch1 pop one element")
- case <-ch2:
- fmt.Println("ch2 pop one element")
- default:
- fmt.Println("default")
- }
此时因为 ch1 和 ch2 都为空,所以 case1 和 case2 都不会读取成功。 则 select 执行 default 语句。
就是因为这个 default 特性, 我们可以使用 select 语句来检测 chan 是否已经满了。
如下:
- ch := make (chan int, 1)
- ch <- 1
- select {
- case ch <- 2:
- default:
- fmt.Println("channel is full !")
- }
因为 ch 插入 1 的时候已经满了, 当 ch 要插入 2 的时候,发现 ch 已经满了(case1 阻塞住), 则 select 执行 default 语句。 这样就可以实现对 channel 是否已满的检测, 而不是一直等待。
比如我们有一个服务, 当请求进来的时候我们会生成一个 job 扔进 channel, 由其他协程从 channel 中获取 job 去执行。 但是我们希望当 channel 瞒了的时候, 将该 job 抛弃并回复 【服务繁忙,请稍微再试。】 就可以用 select 实现该需求。
此外,利用 default 特性,我们可以使用 select 语句将 chan 清空,如下:
- flag: =false
- for {
- select {
- case < -pssScanResponseChan: continue
- default:
- flag = true
- }
- if true == flag {
- break
- }
- }
总结
来源: http://www.phperz.com/article/17/0825/344268.html