如何理解Go程序发生panic时stack trace中的函数参数

Stack Traces In Go这篇文章主要讲了当Golang程序发生panic时,如何读懂stack trace中的函数参数。归纳为下面两个例子:

(1)

package main

import "fmt"

type trace struct{}

func main() {
    slice := make([]string, 2, 4)

    var t trace
    t.Example(slice, "hello", 10)
}

func (t *trace) Example(slice []string, str string, i int) {
    fmt.Printf("Receiver Address: %p\n", t)
    panic("Want stack trace")
} 

执行结果如下:

Receiver Address: 0x570560
panic: Want stack trace

goroutine 1 [running]:
main.(*trace).Example(0x570560, 0xc08201ff50, 0x2, 0x4, 0x4ecc10, 0x5, 0xa)
        C:/Work/gocode/src/Hello.go:16 +0x11d
main.main()
        C:/Work/gocode/src/Hello.go:11 +0xb5
......

可以看到,main.(*trace).Example包含6个参数:第一个(0x570560)是t的地址;接下来三个(0xc08201ff500x20x4)是slice的内容:指向底层数组的指针,lengthcapcity;接下来两个是字符串的内容:同slice相比,缺少了capcity;最后是10这个参数。

(2)

package main
func main() {
    Example(true, false, true, 25)
}

func Example(b1, b2, b3 bool, i uint8) {
    panic("Want stack trace")
}

执行结果如下:

panic: Want stack trace

goroutine 1 [running]:
main.Example(0x19010001)
        C:/Work/gocode/src/Hello.go:7 +0x6b
main.main()
        C:/Work/gocode/src/Hello.go:3 +0x39

上面4个参数每个都占据一个byte,编译器把它们打包在一个word中。

 

 

Go语言利用goroutine实现递归

Recursion And Tail Calls In Go这篇文章讲了用goroutine实现函数递归调用:这样做可以避免过多函数调用引起的堆栈空间的不断增大,感觉很巧妙。以下是例子代码:

package main
import "fmt"

func recursiveCall(product int, num int, ch chan int)  {
    product += num

    if num == 1 {
        ch <- product
        return
    }

    go recursiveCall(product, num - 1, ch)
}

func main()  {
    ch := make(chan int)
    go recursiveCall(0, 4, ch)
    product := <-ch
    fmt.Printf("Product is %d\n", product)
}  

执行结果如下:

Product is 10