声明、初始化代码,我们都懂,但是它背后是怎么实现的呢?
hello.go
- 1 package main
- 2
- 3 func main() {
- 4 var a = "hello"
- 5 var b = []byte(a)
- 6 println(b)
- 7 }
我们写一份上面的代码
go tool compile -S ./hello.go | grep "hello.go:5"
我们看最后一行,CALL 调用了runtime.stringtoslicebyte
- func stringtoslicebyte(buf *tmpBuf, s string) []byte {
- var b []byte
- if buf != nil && len(s) <= len(buf) {
- *buf = tmpBuf{}
- b = buf[:len(s)]
- } else {
- b = rawbyteslice(len(s))
- }
- copy(b, s)
- return b
- }
我们可以看到在这个函数里面使用了copy进行复制
hello.go
- 1 package main
- 2
- 3 import "time"
- 4
- 5 func main() {
- 6 go func () {
- 7 println("hello world")
- 8 }()
- 9 time.Sleep(time.Second * 5)
- 10 }
go tool compile -S ./hello.go | grep "hello.go:6"
在上述图中,我们可以看到编译过程中CALL runtime.newproc
- 1 package main
- 2
- 3 func main() {
- 4 var a = make(chan int, 1)
- 5 a <- 666
- 6
- 7 x := <-a
- 8 println(x)
- 9 }
我们写了一份非阻塞发送和接收的代码
go tool compile -S ./channel_no_block.go
我们可以在chan.go中找到chansend1和chanrecv1的代码实现
- // entry points for <- c from compiled code
- //go:nosplit
- func chanrecv1(c *hchan, elem unsafe.Pointer) {
- chanrecv(c, elem, true)
- }
- // entry point for c <- x from compiled code
- //go:nosplit
- func chansend1(c *hchan, elem unsafe.Pointer) {
- chansend(c, elem, true, getcallerpc())
- }
- 1 package main
- 2
- 3 func main() {
- 4 var ch chan int
- 5 close(ch)
- 6 ch <- 1
- 7 }
我们先定义一份肯定会导致channel panic的代码
go tool compile -S ./channel_panic.go | grep "channel_panic.go:6"
我们可以看到最后一行CALL 是runtime.chansend1
我们进入代码看逻辑
chan.go:202
它自定义了一个plainError的错误类型
我们可以看到有几种情况会抛出这个错误
1.send on closed channel
2.close of nil channel
3.close of closed channel