depguard 是专用于检查 Go 包 import 语句的 linter,通过预设黑白名单规则防止越层或非法依赖;它不分析语法逻辑,只校验 import 路径是否合规,配合分层架构可强制杜绝循环依赖。

depguard 是什么,为什么需要它depguard 是一个专用于检查 Go 包依赖关系的 linter,能防止代码意外引入不被允许的包(比如 log、fmt 在某些高安全或嵌入式场景下需禁用,或禁止业务层直接依赖 database/sql 而必须走 DAO 层封装)。它不分析语法或逻辑,只看 import 语句是否匹配预设的白名单/黑名单规则。
在 .golangci.yml 中启用 depguard 并配置禁止规则
先确保 depguard 已在 linters.enable 列表中;它默认不启用,必须显式加入。配置核心是 linters-settings.depguard 下的 list-type 和 packages:
-
list-type: blacklist 表示“禁止这些包”,最常用
-
packages 是正则表达式列表,不是字符串字面量;例如禁止所有 net/http 及其子包,得写 "^net/http($|/)"
linters:
enable:
- depguard
<p>linters-settings:
depguard:
list-type: blacklist
packages:</p><ul><li>"^log$" # 禁止顶层 log 包</li><li>"^fmt$" # 禁止 fmt(注意:这会影响测试文件,慎用)</li><li>"^net/http($|/)" # 禁止 net/http 及其子包如 net/http/httputil</li><li>"^github.com/some/internal" # 注意点号要转义常见错误:规则不生效或误报太多
- 正则没加锚点导致误匹配:"http" 会命中 github.com/xxx/httpclient,必须用 "^net/http($|/)" 明确边界
- 忘记排除测试文件:如果规则太激进(比如禁 fmt),*_test.go 会大量报错;可在 run.skip-files 加 - "_test\.go$",或改用 whitelist 模式只放行明确允许的包
- depguard 不支持通配符简写(如 net/**),只认 Go 正则,且匹配的是 import path 字符串,不是文件系统路径
- 如果项目用了 Go modules,规则对 replace 或 exclude 后的包路径仍生效,但不会检查 vendor 内的包——除非你没在 run.skip-dirs 里加 - vendor怎么验证 depguard 规则真正在工作
最直接的方法是写一个故意违规的文件,比如:
package main
<p>import (
"fmt" // 违反 "^fmt$" 规则
"net/http" // 违反 "^net/http($|/)" 规则
)</p><p>func main() {}</p>
depguard 已在 linters.enable 列表中;它默认不启用,必须显式加入。配置核心是 linters-settings.depguard 下的 list-type 和 packages:
-
list-type: blacklist表示“禁止这些包”,最常用 -
packages是正则表达式列表,不是字符串字面量;例如禁止所有net/http及其子包,得写"^net/http($|/)"
linters:
enable:
- depguard
<p>linters-settings:
depguard:
list-type: blacklist
packages:</p><ul><li>"^log$" # 禁止顶层 log 包</li><li>"^fmt$" # 禁止 fmt(注意:这会影响测试文件,慎用)</li><li>"^net/http($|/)" # 禁止 net/http 及其子包如 net/http/httputil</li><li>"^github.com/some/internal" # 注意点号要转义常见错误:规则不生效或误报太多
- 正则没加锚点导致误匹配:"http" 会命中 github.com/xxx/httpclient,必须用 "^net/http($|/)" 明确边界
- 忘记排除测试文件:如果规则太激进(比如禁 fmt),*_test.go 会大量报错;可在 run.skip-files 加 - "_test\.go$",或改用 whitelist 模式只放行明确允许的包
- depguard 不支持通配符简写(如 net/**),只认 Go 正则,且匹配的是 import path 字符串,不是文件系统路径
- 如果项目用了 Go modules,规则对 replace 或 exclude 后的包路径仍生效,但不会检查 vendor 内的包——除非你没在 run.skip-dirs 里加 - vendor怎么验证 depguard 规则真正在工作
最直接的方法是写一个故意违规的文件,比如:
package main
<p>import (
"fmt" // 违反 "^fmt$" 规则
"net/http" // 违反 "^net/http($|/)" 规则
)</p><p>func main() {}</p>
package main
<p>import (
"fmt" // 违反 "^fmt$" 规则
"net/http" // 违反 "^net/http($|/)" 规则
)</p><p>func main() {}</p>然后运行:golangci-lint run --no-config --enable=depguard --issues-exit-code=0(加 --no-config 可绕过项目配置,快速测试规则本身)。
如果没报错,说明正则写错了,或者 depguard 没被识别为启用状态(检查输出里是否有 depguard is disabled 提示)。
规则越细粒度,维护成本越高;生产项目建议从 1–2 个关键包开始禁,比如先锁死 os/exec,再逐步扩展。
立即学习“go语言免费学习笔记(深入)”;


















