问题描述:
写一段代码,实现数字和字母被交替打印出来,最终效果如下:
1A2B3C4D5E6F7G8
代码段:
func main() {
//初始化两个通道,一个等待通知执行,另一个在改执行后,通知对方执行;进行交替执行。
letter,number := make(chan int),make(chan int)
wait := sync.WaitGroup{}
go printNum(letter,number)
wait.Add(1)
go printLetter(letter,number,&wait)
number<-1
//阻塞不退出,直到wait.Done()执行
wait.Wait()
}
//打印数字
func printNum(letter chan int,number chan int) {
i := 1
var n int
for{
select {
case n = <-number:
//number 信号为2,退出方法。
if n == 2{
return
}
fmt.Print(i)
i++
letter <- 1
}
}
}
//打印字母
func printLetter(letter chan int,number chan int,wait *sync.WaitGroup) {
i := 'A'
for{
select {
case <-letter:
if i > 'G'{
number <- 2
wait.Done()
return
}
fmt.Print(string(i))
i++
number <- 1
}
}
}
源码解析:
这里用到了两个channel
负责通知,letter负责通知打印字母的goroutine来打印字母,number用来通知打印数字的goroutine打印数字。
wait用来等待字母打印完成后退出循环。
知识点:
1.通道channel的创建和使用:
该例子是创建不带缓冲的通道,channel接收到值后,会阻塞等待直达信号值输出。带缓冲的通过创建例如,区别是在缓冲区满之前,不会阻塞代码往下的执行:
//带缓冲channel
ch := make(chan string, 10)
//创建只读channel
chonlyread := make(<-chan int, 10)
//创建只写channel
chonlywrite := make(chan<- int, 10)
2.select 的使用,以下描述了 select 语句的语法:
- 每个 case 都必须是一个通信
- 所有 channel 表达式都会被求值
- 所有被发送的表达式都会被求值
- 如果任意某个通信可以进行,它就执行,其他被忽略。
- 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
否则:- 如果有 default 子句,则执行该语句。
- 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。