起因是因为犯懒,随手在一个函数体内定义一个类型
func foo() {
type Article = map[string]interface{}
}
看起来好像也很正常,突然有一天在 gowatch 的控制台里看到了
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x1a556a1, 0xe)
/usr/local/Cellar/go/1.12.5/libexec/src/runtime/panic.go:617 +0x72
runtime.newstack()
/usr/local/Cellar/go/1.12.5/libexec/src/runtime/stack.go:1041 +0x6f0
runtime.morestack()
/usr/local/Cellar/go/1.12.5/libexec/src/runtime/asm_amd64.s:429 +0x8f
...
以为是程序出 panic 了,不过仔细看了看,好像不是我的代码,仔细一研究,发现程序还没跑起来,go build
时已经 panic 了。然后经过各种 git stash
,终于发现,原来是因为外面也定义了一个 type Article struct{}
导致的 panic。
印象中函数体内和函数外是可以重名的,而且,即便不可以,也应该编译失败才对,怎么就 panic 了。
于是尝试了一下
如果同时定义两个重名类型,会提示 redeclared in this block
type A struct{}
type A = map[string]string
// A redeclared in this block
如果分开到两个 block,就编译通过了。
type A struct{}
func main(){
type A = map[string]string
}
// build success
奇了个怪。那为什么我的程序会 panic 呢?
又经过尝试,终于发现,在本包内正常调用是可以的,只有当其他包引用此包时才会 panic。而且,如果把函数体内的 type X = Y
改成 type X Y
也是可以编译通过的。
总结起来,两个条件:
- 在两个 block 内同时定义
type X
和type X=
- 在其他包里引入此包
之后,给 goteam 提了个 issue 来反馈这个诡异的 bug。
忧伤的地方来了,自己只能发现 bug,完全不具备追查 bug 产生的原因。
立个 flag 吧,希望有时间可以研究研究编译器相关的一些知识。