Go语言select语句的用法(非常详细)
在 Go 语句中,通道存储数据达到上限的时候,再往通道中写入数据就会提示异常,通道没有存储数据的时候,从通道中读取数据也会提示异常。
在程序运行过程中,我们无法准确预估通道是否有数据或者数据存储是否已达上限,为了解决程序执行异常的问题,可以使用关键字 select 实现。
select 是 Go 语言的一个控制结构语句,语法结构与 switch 语句相似,但仅适用于通道,它可以与 case 和 default 搭配使用,每个 case 必须是一个通信操作,操作方式是执行数据写入或数据读取,也就是说,select 不仅能处理通道阻塞的异常,还能同时处理多个通道变量。
select 语法如下:
根据 select 的语法格式,我们使用多通道的方式实现数据的存储和读写,示例如下:
1) 函数 sent_data() 设有两个参数,分别为 ch 和 ch1,代表两个不同的通道变量,函数执行 5 次循环,每次循环使用 select 和 case 分别对通道变量 ch 或 ch1 执行数据写入操作。
2) 函数 get_data() 的定义过程与 sent_data() 相似,它对通道变量 ch 或 ch1 执行数据读取操作。
3) 主函数 main() 创建通道变量 ch 和 ch1,使用关键字 go 分别对函数 sent_data() 和 get_data() 执行并发操作,最后设置等待延时 5 秒,主要等待并发程序执行完成。
4) 通道变量 ch 和 ch1 设为无缓冲通道,通道数据写入和读取必须同步,否则造成阻塞。函数 sent_data() 和 get_data() 的 select…case 语句没有设置 default 语句,因为通道变量 ch 和 ch1 分别由不同函数操作,必然存在阻塞情况,如果设置 default 语句,程序会因为通道阻塞而无法实现数据的写入和读取。
综上所述,使用 select…case…default 语句可以防止通道阻塞而提示程序异常,同时还能处理多个通道。如果没有设置 default 语句,当通道遇到阻塞的时候,select 也会处于阻塞,这样很容易造成程序无止境地等待,因此在使用 select 语句的时候需考虑这种极端情况。
在程序运行过程中,我们无法准确预估通道是否有数据或者数据存储是否已达上限,为了解决程序执行异常的问题,可以使用关键字 select 实现。
select 是 Go 语言的一个控制结构语句,语法结构与 switch 语句相似,但仅适用于通道,它可以与 case 和 default 搭配使用,每个 case 必须是一个通信操作,操作方式是执行数据写入或数据读取,也就是说,select 不仅能处理通道阻塞的异常,还能同时处理多个通道变量。
select 语法如下:
select { case ch: do something; case ch: do something; /* 定义任意数量的case */ default : /* 可选 */ do something; }语法说明如下:
- select 和 case 是 Go 语言关键字,一个 select 可以搭配多个 case。
- ch 代表通道的数据写入或读取。
- do something 用于执行某个操作。
- default 是 Go 语言关键字,它是可选语句。如果 select 有 default,当所有 case 语句的通道无法操作时,则执行 default 语句的代码块;如果 select 没有 default 并且所有 case 语句的通道无法操作,则 select 将阻塞,直到某个 case 的通道可以执行。
根据 select 的语法格式,我们使用多通道的方式实现数据的存储和读写,示例如下:
package main import ( "fmt" "time" ) func sent_data(ch, ch1 chan int) { for i := 0; i < 5; i++ { select { case ch <- i: fmt.Printf("ch写入数据:%v\n", i) case ch1 <- i: fmt.Printf("ch1写入数据:%v\n", i) } } } func get_data(ch, ch1 chan int) { for i := 0; i < 5; i++ { select { case i := <-ch: fmt.Printf("ch接收数据:%v\n", i) case i := <-ch1: fmt.Printf("ch1接收数据:%v\n", i) } } } func main() { // 创建通道 ch := make(chan int) ch1 := make(chan int) go sent_data(ch, ch1) go get_data(ch, ch1) time.Sleep(5 * time.Second) }运行上述代码,运行结果为:
ch1写入数据:0
ch1接收数据:0
ch接收数据:1
ch写入数据:1
ch1写入数据:2
ch1接收数据:2
ch接收数据:3
ch写入数据:3
ch写入数据:4
ch接收数据:4
1) 函数 sent_data() 设有两个参数,分别为 ch 和 ch1,代表两个不同的通道变量,函数执行 5 次循环,每次循环使用 select 和 case 分别对通道变量 ch 或 ch1 执行数据写入操作。
2) 函数 get_data() 的定义过程与 sent_data() 相似,它对通道变量 ch 或 ch1 执行数据读取操作。
3) 主函数 main() 创建通道变量 ch 和 ch1,使用关键字 go 分别对函数 sent_data() 和 get_data() 执行并发操作,最后设置等待延时 5 秒,主要等待并发程序执行完成。
4) 通道变量 ch 和 ch1 设为无缓冲通道,通道数据写入和读取必须同步,否则造成阻塞。函数 sent_data() 和 get_data() 的 select…case 语句没有设置 default 语句,因为通道变量 ch 和 ch1 分别由不同函数操作,必然存在阻塞情况,如果设置 default 语句,程序会因为通道阻塞而无法实现数据的写入和读取。
综上所述,使用 select…case…default 语句可以防止通道阻塞而提示程序异常,同时还能处理多个通道。如果没有设置 default 语句,当通道遇到阻塞的时候,select 也会处于阻塞,这样很容易造成程序无止境地等待,因此在使用 select 语句的时候需考虑这种极端情况。