一、switch语句
go中switch的几种用法如下面代码示例所示:
package main
import (
"fmt"
)
func main() {
var x interface{}
//用type-switch语句来判断某个interface变量中实际存储的变量类型
//写法一:
switch i := x.(type) { //带初始化语句
case nil:
fmt.Printf("x的类型:%T\r\n", i)
case int:
fmt.Printf("x是int类型")
case float64:
fmt.Printf("x是float64类型")
case func(int) float64:
fmt.Printf("x是func(int)类型")
case bool, string:
fmt.Printf("x是bool或string类型")
default:
fmt.Printf("未知类型")
}
//写法二
var j = 0
switch j {
case 0:
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
default:
fmt.Println("def")
}
//写法三
var k = 0
switch k {
case 0:
println("fallthrough")
fallthrough
/*
Go的switch非常灵活,表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项;
而如果switch没有表达式,它会匹配true。
Go里面switch默认相当于每个case最后带有break,
匹配成功后不会自动向下执行其他case,而是跳出整个switch,
但是可以使用fallthrough强制执行后面的case代码。
*/
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
default:
fmt.Println("def")
}
//写法四
var m = 0
switch m {
case 0, 1:
fmt.Println("1")
case 2:
fmt.Println("2")
default:
fmt.Println("def")
}
//写法五
var n = 0
switch { //省略条件表达式,可当成if...else if...else
case n > 0 && n < 10:
fmt.Println("i > 0 and i < 10")
case n > 10 && n < 20:
fmt.Println("i > 10 and i < 20")
default:
fmt.Println("def")
}
}
执行结果:
二、select语句
1. select语句类似于switch语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
select可以监听channel的数据流动,用于处理异步IO操作,它最大的限制就是每个case语句里必须是一个IO操作(channel操作)
select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。一个默认的子句应该总是可运行的。
2. select的语法可用以下几句话简单表示:
(1) 每个case都必须是一个通信
(2) 所有channel表达式都会被求值
(3) 所有被发送的表达式都会被求值
(4) 如果任意某个通信可以执行,它就执行;其他被忽略
(5) 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行
否则:
(1) 如果有default子句,则执行该语句。
(2) 如果没有default子句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。
3. 在一个select语句中,Go会按顺序从头到尾评估每一个发送和接收的语句。如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可执行的语句中任意选择一条来使用。
如果没有任何一条语句可以执行(即所有通道都被阻塞),那么有两种可能的情况:
(1)如果给出了default语句,那么就会执行default的流程,同时程序的执行会从select语句后的语句中恢复(即继续执行select之外的代码)。
(2)如果没有default语句,那么select语句将被阻塞,直到至少有一个case可以进行下去
几种用法:
1. 基本用法
//1.基本使用
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, "from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3):
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
2. 几种典型用法
(1) 超时判断
//比如在下面的场景中,使用全局resChan来接收response,如果时间超过3s,resChan中还没有数据返回,则第二条case将执行
var resChan = make(chan int)
//do request
func testTimeOut() {
select {
case data := <-resChan:
fmt.Println(data)
case <-time.After(time.Second * 3):
fmt.Println("request time out")
}
}
(2)遇到特定事件时退出程序
//2.退出
var shouldQuit = make(chan struct{})
func testExit() {
select {
case <-shouldQuit:
//cleanup
return
}
}
(3) 判断channel是否阻塞
//3.判断channel是否阻塞
func testBlock() {
ch := make(chan int, 5)
data := 0
select {
case ch <- data:
default:
fmt.Println("丢弃data")
}
}