Go新手实战常见三大坑:一是go run找不到main包,需将main.go置于cmd/appname/目录并确保无构建约束;二是HTTP路由404,须检查中间件注册顺序、handler签名匹配及路径斜杠;三是goroutine阻塞,主因未配对channel收发或缺超时控制。

Go新手跑第一个实战项目,八成会卡在几个固定环节:不是 go run 报错找不到包,就是 HTTP 服务起来但访问 404,又或者 goroutine 看似跑起来了却没输出、内存悄悄涨上去——这些问题不难,但排查路径模糊,容易反复折腾。
go run 找不到 main 包或命令未定义?检查 cmd/ 目录结构和入口文件命名
很多新手按教程建了 main.go,却放在项目根目录或 pkg/ 下,go run 就会报 no Go files in current directory 或 cannot find package。Go 要求可执行程序必须有 package main 且含 func main(),同时 go run 默认只扫描当前目录下的 .go 文件。
- 正确做法是把启动文件放进
cmd/(例如/main.go cmd/api/main.go),再用go run cmd/api/main.go - 如果项目用了模块(
go.mod),确保main.go所在目录没有被//go:build或// +build条件编译排除 - 别在
internal/或pkg/里放main.go——这些目录本就不允许被外部引用,更不会被go run主动发现
HTTP 路由 404 或 handler 不触发?确认框架注册顺序与方法匹配
用 Gin、Echo 或 net/http 写接口时,明明写了 router.GET("/user", handler),curl 却返回 404,常见原因不是路由写错了,而是注册时机或中间件拦截了请求。
- Gin 中,
router.Use()添加的中间件必须在router.GET()之前调用,否则中间件根本收不到请求 - 检查 handler 函数签名是否匹配框架要求,比如 Gin 要求
func(*gin.Context),传成func(http.ResponseWriter, *http.Request)就静默失败 - 路径末尾斜杠敏感:
GET "/users"和GET "/users/"是两个不同路由;Gin 默认不自动重定向,需显式配置router.RedirectTrailingSlash = true
goroutine 启动后“消失”或阻塞?盯紧通道收发配对和超时控制
这是新手并发项目里最隐蔽的坑:协程启了,日志没打,也不 panic,程序就卡住不动了。典型原因是 unbuffered channel 发送后没人接收,goroutine 永久阻塞在 ch 上。
立即学习“go语言免费学习笔记(深入)”;
- 避免裸用
make(chan int),优先考虑带缓冲通道:ch := make(chan int, 1),或加select+default防死锁 - 所有
go func() { ... }()里涉及 channel 操作的,必须确保有对应接收方,且接收逻辑不能被提前 return 绕过 - 用
context.WithTimeout包裹 goroutine 执行逻辑,防止因下游依赖挂起导致整个协程组不可控
func badExample() {
ch := make(chan int)
go func() {
ch <- 42 // 永远阻塞:没人从 ch 接收
}()
// 程序卡在这里,或直接退出,协程泄漏
}
func goodExample() {
ch := make(chan int, 1) // 缓冲为 1,发送不阻塞
go func() {
ch <- 42
}()
select {
case v := <-ch:
fmt.Println(v)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
}
}
环境变量读取为空或配置加载失败?验证 .env 加载时机与作用域
本地调试时,os.Getenv("DB_HOST") 返回空字符串,但 .env 文件明明写了。问题往往出在加载顺序:Go 本身不自动读 .env,得靠第三方库(如 godotenv),而它必须在任何使用环境变量的代码之前调用。
- 在
cmd/最顶部(/main.go package main下一行)就调用godotenv.Load(),不要放在init()或某个 config 包里 - 注意
godotenv.Load(".env.local")这类显式指定路径时,路径是相对于当前工作目录(os.Getwd()),不是源码目录 - Docker 环境下,
.env文件默认不进容器,要么 COPY 进去,要么改用docker-compose.yml的environment:字段直接注入
真正卡住新手的,往往不是语法不会,而是这些“看不见的约定”——目录结构、加载顺序、channel 配对、环境变量作用域。它们不报错,只让程序行为偏离预期。多看一眼 go list -f '{{.Dir}}' . 输出的当前包路径,比重写三遍 handler 更管用。










