go子包路径必须以go.mod中定义的模块名为根,import语句需写全路径如“example.com/app/handlers”,不支持相对导入或裸包名,且须避免循环依赖,构建时需显式指定子包路径。

子包路径必须以模块路径为根
Go 的子包不是靠文件夹相对位置决定的,而是由 import 语句中的完整路径决定的。这个路径必须从模块根开始,也就是 go.mod 文件里定义的 module 名称起始。
比如模块声明是 module github.com/user/project,那么:
-
github.com/user/project/utils是合法子包 -
github.com/user/project/api/v1也是合法子包 - 但不能写
import "./utils"或import "utils"—— Go 不支持相对导入或裸包名
同一模块内子包 import 写法要带模块前缀
即使子包和当前文件在同一个本地目录树下,import 也必须写全路径,不能省略模块名。
错误示例(假设模块是 example.com/app):
立即学习“go语言免费学习笔记(深入)”;
import "handlers" // ❌ 找不到包 import "./handlers" // ❌ 语法错误
正确写法:
import "example.com/app/handlers" // ✅ 即使 handlers/ 在当前目录下
这是因为 Go 编译器只认 GOPATH 或模块路径下的导入路径,不解析文件系统相对关系。
子包间互相引用时路径不能循环依赖
Go 不允许两个包直接或间接地相互 import。比如 a 导入 b,而 b 又导入 a,编译会报错:
import cycle not allowed
常见踩坑点:
- 把接口定义放在
model包,实现却放在service包,又让model反向依赖service去调用某个函数 —— 这容易隐式引入循环 - 子包
internal/auth和internal/db都试图导入对方的工具函数
解决方式:把共享类型或接口提到更上层包(如根包或 pkg/),或用参数传入依赖,避免 import 循环。
go build / go run 时不会自动发现子包
运行命令默认只编译当前目录下的 .go 文件,不会递归扫描子目录。所以:
-
go run main.go不会自动包含handlers/下的代码,除非main.go显式import它 -
go build在子包目录下执行,只会构建那个子包(生成 .a 文件),不是可执行文件 - 要构建整个应用,应在模块根目录运行
go build -o bin/app ./cmd/app(假设入口在cmd/app/main.go)
子包本身一般不直接运行,它们是被其他包 import 后参与编译的。只有含 func main() 的包才能作为主程序。
最容易忽略的是:子包路径写错时,报错信息往往只说 cannot find package,但不会提示你“你少写了模块前缀”——得自己核对 go.mod 的 module 行和 import 路径是否完全匹配,包括大小写和斜杠方向。










