go.work文件必须置于工作区根目录,否则完全失效;它不支持嵌套,仅当前目录下的go.work被识别,子目录中放置将导致workspace模式不生效。

go.work 文件必须放在工作区根目录
不放对位置,go work 就完全失效。它不像 go.mod 可以嵌套生效——go.work 只认当前目录及其子目录下的模块,且必须由顶层目录的 go.work 显式声明。如果你把文件建在 service-a/ 里,go run 或 go test 会照常读 service-a/go.mod,根本不会感知到 workspace 的存在。
正确做法是:所有子模块(如 service-a、lib-core、cli-tool)都作为同级目录,统一放在一个空目录下,然后在这个空目录里执行:go work init ./service-a ./lib-core ./cli-tool
生成的 go.work 内容类似:
go 1.23 <p>use ( ./service-a ./lib-core ./cli-tool )
这样,当你在任意子目录下运行 go list -m,就能看到 lib-core 被识别为本地路径而非远程版本;go build 也会自动从本地加载其代码,无需 replace 指令。
立即学习“go语言免费学习笔记(深入)”;
lib-core 的 go.mod 必须有明确 module path
如果 lib-core/go.mod 里写的是 module lib-core 这种相对路径,其他模块导入时会失败——Go 工具链要求所有模块路径必须是全局唯一、可解析的字符串(通常带域名前缀),否则 go mod tidy 会报错:require lib-core: version "v0.0.0" invalid: unknown revision v0.0.0。
所以 lib-core/go.mod 第一行必须是类似:module github.com/yourname/myproject/lib-core
而其他模块(比如 service-a)导入时,也必须用这个完整路径:import "github.com/yourname/myproject/lib-core"
注意三点:
- 路径要和你本地目录结构一致(即
lib-core目录得在github.com/yourname/myproject/下) - 不要用
replace去“修复”路径不匹配——workspace 模式下replace是冗余甚至冲突的 - IDE(如 VS Code + Go extension)依赖这个路径做跳转和补全,路径错会导致整个开发体验断裂
内部共享逻辑应放进 internal/ 而非直接暴露
如果 lib-core 里混着大量仅供本项目使用的工具函数(比如数据库连接池初始化、HTTP 中间件封装),却放在顶层包(如 lib-core 根目录),那其他子模块一导入就可能误用这些不稳定接口。这不是 workspace 的问题,而是设计漏洞。
推荐结构:
lib-core/
├── go.mod
├── internal/
│ └── db/ # 只供 service-a/service-b 使用
│ └── pool.go
└── pkg/
└── api/ # 对外稳定契约,可被外部项目 import
└── client.go这样:
-
service-a可以安全导入github.com/yourname/myproject/lib-core/internal/db(只要它在 workspace 内) - 外部用户只能 import
github.com/yourname/myproject/lib-core/pkg/api,不会看到或依赖内部实现 -
internal/目录天然受 Go 编译器保护,一旦有人试图从 workspace 外导入,会直接报错:import "github.com/yourname/myproject/lib-core/internal/db" is not allowed
CI 构建时需显式启用 workspace
本地开发靠 go.work 自动生效,但 CI 环境(如 GitHub Actions、GitLab CI)默认不识别它——除非你明确告诉构建命令:“请按 workspace 模式跑”。否则 CI 会 fallback 到每个模块独立的 go.mod,导致 lib-core 被当成未发布的 v0.0.0,编译失败。
解决方法是在 CI 脚本中加一句:go work use ./lib-core(或直接 go work use .)
更稳妥的做法是,在 CI 步骤开头统一激活 workspace:
- name: Setup Go workspace
run: |
go work init .
go work use ./service-a ./lib-core ./cli-tool注意:不要在 CI 中运行 go work sync——它会把 workspace 依赖写进各子模块的 go.mod,污染本地开发状态。
真正容易被忽略的是:workspace 模式下,go list -m all 输出的模块列表和非 workspace 下完全不同,CI 中所有依赖检查、版本比对、安全扫描工具(如 gosec、govulncheck)都必须适配这一差异,否则会漏报或误报。


















