go语言switch/select中表达式求值顺序
switch/select语句中表达式的求值属于惰性求值,在需要进行求值时才会对表达式进行求值。这样
做的目的是降低程序消耗,对性能提升有一定的帮助。
package main import "fmt" func expr(n int) int { fmt.Println(n) return n } func main() { switch expr(2) { case expr(1), expr(2), expr(3): fmt.Println("This is case1") fallthrough case expr(4): fmt.Println("This is case2") } }
运行程序结果:
go run .\evaluation_order.go 2 1 2 This is case1 This is case2
对于switch- case语句而言,首先进行求值的是switch后边的表达式expr(2),这个表达式求值时输出2
接下来按照从上到下、从左到右的顺序对case语句中的表达式进行求值。如果某个表达式的结果与switch表达式的结果一致,那么停止求值。expr(3)求值被忽略。
fallthrough直接跳到下一个case执行语句中,忽略了case表达式expr(4)的求值。
go语言中的select为我们提供了一种在多个channel间实现“多路复用”的机制,时编写go语言并发程
序最常用的并发原语之一。select-case语句中表达式求值顺序:
package main import ( "fmt" "time" ) func getAReadOnlyChannel() <-chan int { fmt.Println("This is getAReadOnlyChannel") c := make(chan int) go func() { time.Sleep(5 * time.Second) c <- 1 }() return c } func getASlice() *[5]int { fmt.Println("This is getASlice") var s [5]int return &s } func getAWriteOnlyChannel() chan<- int { fmt.Println("This is getAWriteOnlyChannel") return make(chan int) } func getANumToChannel() int { fmt.Println("This is getANumToChannel") return 2 } func main() { select { // 从channel接收数据 case (getASlice())[0] = <-getAReadOnlyChannel(): fmt.Println("receive something from a readonly channel") // 将数据发送到channel case getAWriteOnlyChannel() <- getANumToChannel(): fmt.Println("send something to a write only channel") } }
执行结果:
go run .\evaluation_order.go This is getAReadOnlyChannel This is getAWriteOnlyChannel This is getANumToChannel This is getASlice receive something from a readonly channel
①select执行开始时,首先所有的case表达式都会被按出现的先后顺序求值一遍。但是,位于case等号左边的从channel接收数据的表达式不会被求值。即getASlice()不会被执行。
②如果选择要执行的是一个从channel接收数据case,那么该case等号左边的表达式在接收前才会被求值。该例中,在getAReadOnlyChannel创建的goroutine在5s后向channel中写入一个int值后,输出“This is getASlice”。这也是一种惰性求值。
Go语言基础及实战 文章被收录于专栏
Go语言学习笔记、语法知识、技术要点和个人理解及实战