package 是代码组织最小单位,module 是依赖管理基本单元;标准库包如 fmt 无需 go mod init,而自定义包必须匹配 module 路径,否则报错;package 名与目录名不一致易致维护混乱;多 main 包或混用 go.mod 会破坏模块解析。
package 是代码组织的最小单位,module 是依赖管理的基本单元——二者不在同一抽象层级,不能互换或混用。
因为 fmt 是 Go 标准库包,它属于内置模块(std),不参与 module 依赖解析。Go 编译器直接识别标准包路径,无需通过 go.mod 查找或版本控制。
fmt、net/http、encoding/json 开头的导入,都走标准库路径,与当前项目是否启用 module 无关import "myproject/utils",Go 就必须通过 module 路径定位该包——此时若没 go.mod 或路径不匹配,会报错 cannot find module providing package myproject/utils
GOPATH 下,只要启用了 module(如设置了 GO11
1MODULE=on),Go 仍优先按 go.mod 解析,忽略 GOPATH/src
编译能过,但 import 路径和使用方式会割裂,极易引发维护混乱和 CI 失败。
studentmanage,但 studentmanage/add.go 写的是 package student → 外部要 import "your-module/studentmanage",却得用 student.Add(),路径和包名不统一package main(哪怕只是测试文件),go build 会报错 multiple main packages
go list -f '{{.Name}}' ./... 会按实际 package 声明返回名字,不是目录名——CI 中做自动化检查时容易误判因为 Go 的 import 路径 = module path + 相对目录路径,这是 module 机制的硬性解析规则。
myapp/
├── go.mod # module myapp
├── main.go # package main; import "myapp/handler"
└── handler/
└── api.go # package handlermain.go 中写 import "myapp/handler" 才合法;写 import "./handler" 或 import "handler" 都会失败go.mod 里是 module github.com/user/myapp,那正确 import 就得是 import "github.com/user/myapp/handler"
replace:在 go.mod 加一行 replace example.com/old => ./local-fix
最容易被忽略的一点:一个目录下可以有多个 .go 文件,但它们的 package 声明必须完全一致;而一个 module 可以包含几十个 package,但 go.mod 只有一个——别试图在一个项目里建多个 go.mod,除非你明确要做多 module 工作区(go work init)。否则,子目录里的 go.mod 会被视为独立 module,导致 import 解析断裂。