复现问题
首先来看问题是怎么出现的。在gotest
目录下,有testundefined.go
和main.go
文件。其中main.go
文件引用了testundefined.go
中的结构体Test
。编写没有语法错误,但是在运行go run
命令时,却报错:
# command-line-arguments
.\main.go:6:10: undefined: Test
testundefined.go文件:
package main
type Test struct {
Name string
Year int
}
main.go文件:
package main
import "fmt"
func main() {
test := Test{
"benben",
2015,
}
fmt.Println(test)
}
原因查找
既然是在运行go run
命令的时候出错,那么首先来看执行命令的入口。位于$GOPATH/src/cmd/go
目录下的main.go
文件,是命令运行的入口。该文件导入了cmd/go/internal/run
包,那么势必要运行该包下的初始化函数。
func init() {
CmdRun.Run = runRun // break init loop
work.AddBuildFlags(CmdRun)
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
}
初始化函数第一行是运行run命令的函数:
首先它会搭建运行环境,然后检测文件是否合乎规则(是否是.go
文件,是否是_test.go
文件等)。如果检测通过,它会创建一个用于构建Go文件集合的包(GoFilesPackage接口实现)。
接着将创建的集合加入导入栈(ImportStack []string
)中进行加载,加载完成后从栈中取出。
...
stk.Push("main")
pkg.load(&stk, bp, err)
stk.Pop()
...
由于启动的时候只传入了一个参数main.go
,而依赖的文件testundefined.go
没有被导入。这样main
函数在运行时就找不到testundefined.go
文件中的Test
结构体。
解决方法
当同一个包下,文件存在依赖关系时,应该把依赖的文件都传入加载参数里面。例如:
D:\gotest>go run main.go testundefined.go
{benben 2015}