一、条件语句 select
1.1 select 介绍
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
select { //不停的在这里检测
case <-chanl : //检测有没有数据可以读
//如果chanl成功读取到数据,则进行该case处理语句
case chan2 <- 1 : //检测有没有可以写
//如果成功向chan2写入数据,则进行该case处理语句
//假如没有default,那么在以上两个条件都不成立的情况下,就会在此阻塞//一般default会不写在里面,select中的default子句总是可运行的,因为会很消耗CPU资源
default:
//如果以上都没有符合条件,那么则进行default处理流程
}
select 语句类似于 switch 语句,但是 select会随机选择一个可运行的 case,如果没有 case可以运行,那么它将一直阻塞直到有 case可用。select 语句中的每个 case 都必须是一个通信操作,要么是发送要么是接收,如果有多个 case 都可以运行,Select 会随机公平地选择出一个执行,其它的不会执行;如果有 default 子句,那么执行该语句;如果没有 default 子句,那么 select 将阻塞,直到某个通信可以运行。
//实例
func main() {
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.Println("no communication\n")
}
}
//output
no communication
1.2 select 典型用法
1.2.1 超时判断
//比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行
var resChan = make(chan int)
// do request
func test() {
select {
case data := <-resChan: //接收到数据
doData(data)
case <-time.After(time.Second * 3): //超时
fmt.Println("request time out")
}
}
func doData(data int) {
//...
}
1.2.2 线程/协程 退出
//主线程(协程)中如下:
var shouldQuit=make(chan struct{})
fun main(){
{
//loop
}
//...out of the loop
select {
case <-c.shouldQuit:
cleanUp()
return
default:
}
//...
}
//再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
close(shouldQuit)
1.2.3 判断channel是否阻塞
//在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断
ch := make (chan int, 5)
//...
data:=0
select {
case ch <- data:
default:
//做相应操作,比如丢弃data。视需求而定
}
二、循环语句 range
//例1
func main() {
a := [3]int{0, 1, 2}
for i, v := range a { // index、value 都是从复制品中取出。
if i == 0 { // 在修改前,我们先修改原数组。
a[1], a[2] = 999, 999
fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。
}
a[i] = v + 100 // 使用复制品中取出的 value 修改原数组。
}
fmt.Println(a) // 输出 [100, 101, 102]。
}
//output
[0 999 999]
[100 101 102]
func main() {
s := []int{1, 2, 3, 4, 5}
for i, v := range s { // 复制 struct slice { pointer, len, cap }。
if i == 0 {
s = s[:3] // 对 slice 的修改,不会影响 range,这里不是对底层数据的修改,所以无影响
s[2] = 100 // 对底层数据的修改。
}
println(i, v)
}
}
//output
0 1
1 2
2 100
3 4
4 5
对数组使用 range-for 会复制一份底层数组,index、value均从复制品中取出;slice 作为引用类型被 range-for 时不会复制底层数据,对于底层数据的修改会影响到 range 循环。
type student struct {
name string
age int
}
func main() {
m := make(map[string]*student)
stus := []student{
{name: "pprof.cn", age: 18},
{name: "测试", age: 23},
{name: "博客", age: 28},
}
for _, stu := range stus {
m[stu.name] = &stu //这里每次取复制对象的地址,都是同一个地址,取得最后循环到的对象的值
}
for k, v := range m {
fmt.Println(k, "=>", v.name)
}
}
//output
pprof.cn => 博客
测试 => 博客
博客 => 博客
标签:11,控制,name,int,流程,999,case,range,select
From: https://www.cnblogs.com/istitches/p/17748647.html