deadcode 是目前最可靠的选择,它基于前向可达性分析识别未调用的私有函数,而 go 编译器、go build 和 goland 内置检查均无法覆盖此类死代码。

deadcode 工具是目前最可靠的选择
Go 编译器本身不报告未调用的私有函数,go build 也不会警告或删除它们——哪怕函数在本包内完全没被引用。GoLand 内置的“未使用符号”检查只覆盖导出符号(首字母大写)和局部变量,对 helper()、cleanup() 这类小写私有函数视而不见。
真正能识别这类死代码的是外部工具 deadcode,它基于前向可达性分析,从 main 和测试入口出发,追踪所有实际可能被执行的调用路径。
- 安装:
go install github.com/tsenart/deadcode@latest - 运行:
deadcode ./(扫描整个模块)或deadcode ./internal/utils(指定子目录) - 输出示例:
internal/utils/file.go:42:6: unused func parseConfig,直接带行号和函数名
在 GoLand 中集成 deadcode 并一键触发
手动敲命令太慢,建议把 deadcode 配成 External Tool,绑定快捷键,双击就能跑。
- 打开
Settings → Tools → External Tools,点击+添加新工具 -
Name: 填Find dead code;Program: 填deadcode(确保已加入 PATH) -
Arguments: 填$ProjectFileDir$(当前项目根目录);Working directory: 填$ProjectFileDir$ - 勾选
Open console for tool output,方便查看结果 - 设置快捷键:选中该工具 → 点击
Advanced Options → Keyboard Shortcut,比如设为Ctrl+Alt+D
之后在任意位置按快捷键,GoLand 就会自动执行 deadcode ./,结果直接出现在底部 Run 窗口,点击错误行可跳转到源码。
GoLand 2026.1.1 是 2026.1 发布后的首个维护修正版本,适合已经开始体验 2026.1 新功能并希望同步补丁的开发者。它更适合用于入门项目、现有项目迁移测试和 IDE 行为验证。
别信“全局搜索”结果就等于“没被调用”
很多人用 GoLand 的 Ctrl+Shift+0F 全局搜函数名,发现没匹配就删——这是高危操作。以下情况会让搜索失效,但函数仍被间接引用:
- 函数被赋值给空接口:
var _ interface{} = helper,deadcode会误报,但不能删 - 函数实现了某个接口(哪怕没显式调用):
var _ io.Closer = &MyStruct{},只要结构体方法集包含该函数,它就算“活跃” - 函数名被字符串硬编码:
fmt.Errorf("failed in %s", "helper")或用于runtime.FuncForPC日志追踪 - 函数在
init()里被调用,或参与包级变量初始化:var cfg = loadConfig()
这些场景下,deadcode 输出的 “unused func” 是假阳性,必须人工 review 上下文再决定是否删除。
删之前务必验证三个隐式调用点
死代码清理不是机械删除,而是验证契约是否断裂。尤其注意这三类容易被忽略的“静默调用”:
-
init()函数里是否调用了它?哪怕只有一行helper(),也不能删 - 是否被反射使用?比如
reflect.ValueOf(helper).Call(nil)或通过 JSON/YAML 配置驱动的 handler 注册 - 是否作为插件机制的一部分?例如
plugin.Open加载的模块里可能通过 symbol 名称查找并调用它
删掉一个看似孤立的 validateInput(),可能导致某个 init 阶段 panic,或者测试用例因缺少校验逻辑而静默失败——这种问题往往在线上才暴露。










