go run 编译后立即在临时目录执行并清理,os.Args[0]指向临时路径,适合开发调试;go build 生成稳定可执行文件,默认置于当前目录,os.Args[0]即为二进制路径,适合生产部署。
go 命令不是“运行就能用”,而是按用途严格分场景的工具链——写错命令或忽略上下文,轻则报错,重则生成错误二进制或静默失败。
go run 和 go build 的核心区别在哪
两者都编译代码,但行为完全不同:go run 编译后立即执行并清理临时文件;go build 编译后生成可执行文件,不自动运行。
-
go run main.go适合开发调试:改完即跑,不用管输出名,但无法复用二进制 -
go build -o myapp main.go适合交付:生成myapp文件,可拷给他人、部署到服务器、加 systemd 管理 - 如果目录下有多个
.go文件(比如main.go+utils.go),go run必须列全:go run main.go utils.go,漏一个就报 undefined: xxx -
go build默认会自动找当前目录所有.go文件(除 test 文件),所以只需go build即可,更省心
为什么 go run 报错 “package main is not a main package”
这是最常见的入门卡点,根本原因不是语法错,而是 Go 对“可执行程序”有硬性约定:
- 必须存在
package main—— 不能是package utils或package v1 - 必须定义
func main()—— 名字大小写敏感,Func Main()或func mainn()都无效 - 文件不能放在
$GOPATH/src/xxx以外的随意路径里(Go 1.16+ 启用 module 后放宽,但若没go.mod,仍可能 fallback 到 GOPATH 模式) - 如果项目根目录没有
go.mod,且当前路径不在$GOPATH/src下,go run可能拒绝识别为 module,进而无法解析 import 路径
go mod init 什么时候必须执行
不是“建议”,而是现代 Go 项目的事实标准。不执行会导致三类问题:
- 第三方包导入失败:比如
import "github.com/gin-gonic/gin"在无go.mod时会被当成相对路径,报cannot find package - 版本锁定缺失:没有
go.sum,每次go get可能拉取不同 commit,CI 构建结果不可重现 -
go run/go build在子目录下可能误判主包路径,尤其当目录名含点号(如api.v1)或与 import 路径不一致时 - 执行方式很简单:
go mod init example.com/myapp(模块路径不必真实存在,但应符合域名习惯)
main 函数里 panic 了,为什么看不到完整堆栈
默认情况下,go run 或直接运行二进制时,panic 只打印错误信息和最顶一层调用,深层调用被截断。这不是 bug,是 Go 的默认行为。
- 加
-gcflags="-l"可禁用内联,让堆栈更清晰(开发期调试用):go run -gcflags="-l" main.go - 真正要定位问题,得靠
go tool trace或pprof,但日常够用的是:在 panic 前加debug.PrintStack()(需import "runtime/debug") - 注意:生产环境不要留
debug.PrintStack(),它会暴露内部路径和变量名,有安全风险 - 如果 panic 来自第三方库(比如
json.Unmarshal(nil, &v)),堆栈往往只显示库内部行号,此时得结合go list -m all查版本,并确认是否已知 issue
package main、强制 go mod init)都是为了在中大型项目里避免隐式依赖和构建歧义——越早适应这些边界,后期踩的坑越少。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











