1、Reader
io
包指定了 io.Reader
接口,它表示从数据流的末尾进行读取。
Reader接口包含的方法
func (T) Read(b []byte) (n int, err error)
Read
用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流的结尾时,它会返回一个 io.EOF
错误,如下:
package main import ( "strings" "fmt" "io" ) func main() { //创建字符串mujiutian r:= strings.NewReader("mujiutian!") //创建byte类型的切片,长度为8 b:= make([]byte,8) //循环遍历,直到遇到数据流的结尾时,他会返回一个io.EOF错误 for { n,err := r.Read(b) fmt.Printf("n= %v err = %v b= %v \n",n,err,b) if err == io.EOF { break } } }
结果:
n= 8 err = <nil> b= [109 117 106 105 117 116 105 97] n= 2 err = <nil> b= [110 33 106 105 117 116 105 97] n= 0 err = EOF b= [110 33 106 105 117 116 105 97]
第一次读取了8个字节数【mujiutia】,第二次数据了两个字节数【n!】,最后0个。
2、go并发,goroutine
package main import ( "time" "fmt" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(10 * time.Millisecond) fmt.Println(s) } } func main() { go say("osc") say("mujiutian") }
结果,这个结果也是随机的:
mujiutian osc osc mujiutian osc mujiutian osc mujiutian osc mujiutian
从随机的结果也可以看到,这是两个单独的线程在执行,不然一个线程的话会有先后顺序,有截图如下:
2、信道chan
2.1 信道是带有类型的管道,你可以通过它用信道操作符 <-
来发送或者接收值。
2.2 “箭头”就是数据流的方向。
2.3 和映射与切片一样,信道在使用前必须创建。
package main import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // 将和送入 c } func main() { s := []int{8, 2, 8, -9, 4, 0} c := make(chan int) d := make(chan int) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], d) x, y := <-d, <-c // 从 c 中接收 fmt.Println(x, y, x+y) }
结果为:-5 18 13
3、带缓冲的chan,固定长度
仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。
这句话的意思就是如果发送数据的长度大于接收数据信道的长度,会发生阻塞,同样,当发送数据为信道时,而它为空,也出现阻塞,简单理解就是报错。
import "fmt" func main() { ch := make(chan int, 1) ch <- 1 fmt.Println(<-ch) }
现在是一个长度的信道,结果为:1
现在变成两个,发送数据大于信道长度,如下:
package main import "fmt" func main() { ch := make(chan int, 1) ch <- 1 ch <- 8 fmt.Println(<-ch) fmt.Println(<-ch) }
结果报错:
当信道为空时,作为发送数据一方也同样会报错,如下:
func main() { ch := make(chan int, 1) fmt.Println(<-ch) }
4、range 和 close
发送者可通过 close
关闭一个信道来表示没有需要发送的值了。接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完
v, ok := <-ch
之后 ok
会被设置为false,也就是信道关闭的意思。
只有发送者才能关闭信道,而接收者不能。
向一个已经关闭的信道发送数据会引发程序恐慌(panic)信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有值需要发送的时候才有必要关闭,例如终止一个 range
循环
package main import "fmt" func fibonacci(n int, c chan int) { x, y := 0, 1 for i := 0; i < n; i++ { c <- x x, y = y, x+y } close(c) } func main() { c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } }
5、select语句
package main import "fmt" func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fibonacci(c, quit) }
结果为:
0 1 1 2 3 5 8 13 21 34 quit
select
语句使一个 Go 程可以等待多个通信操作。就是通信线操作,go成后执行。
当 select
中的其它分支都没有准备好时,default
分支就会执行。和java的switch中的default一样。
请发表评论