如何在 Go 中正确编译和运行多个本地源文件

go 不支持通过单个文件(如 `go run b.go`)自动加载同包的其他本地 `.go` 文件;必须显式列出所有参与编译的源文件,或使用目录模式(如 `go run .`)才能使跨文件的函数调用生效。

在 Go 中,同一包下的多个 .go 文件天然属于同一个编译单元——但前提是它们同时被编译器感知。当你执行 go run b.go 时,Go 工具链仅读取 b.go 一个文件,并不会自动扫描同目录下其他 .go 文件(即使它们同属 package main)。因此 foo() 在 b.go 中未定义,导致编译错误:undefined: foo。

✅ 正确做法有以下两种:

  1. 显式列出所有相关文件

    go run a.go b.go

    这会将两个文件一并编译、链接并运行,foo() 可被正常解析和调用。

  2. 使用目录路径(推荐,更可扩展)

    go run .

    . 表示当前目录,Go 会自动收集该目录下所有属于 main 包的 .go 文件(排除测试文件 *_test.go),等效于手动列出全部源码文件。

⚠️ 注意事项:

  • 所有文件必须声明相同的 package main(或其他一致的包名),且不能存在包名冲突;
  • 文件中不能有重复的函数/变量定义(例如两个 func main() 会报错 multiple main functions);
  • go build 和 go test 同样遵循此规则:单文件模式不自动包含同包其他文件;
  • 若项目结构变复杂(如含子目录、多模块),应使用 go mod init 初始化模块,并通过标准包导入机制(而非文件拼接)组织代码。

? 小结:Go 的设计强调显式依赖和确定性构建。它不隐式“包含”或“导入”本地文件,而是由构建命令明确指定输入源。养成使用 go run . 开发小型命令行程序的习惯,既简洁又符合 Go 工程实践。