Delve需先安装go install github.com/go-delve/delve/cmd/dlv@latest,再用dlv debug调试当前main包或dlv attach 附加进程;断点用b main.go:12等命令设置,n/s/c控制执行,p/locals/stack查看变量与调用栈。

怎么启动Delve调试Go程序
Delve不是go run那样的内置命令,得先装好才能用。没装的话dlv命令会报command not found。推荐用go install github.com/go-delve/delve/cmd/dlv@latest安装,别用brew install delve——macOS上它常因签名问题卡在启动阶段。
启动方式分两种场景:
- 调试当前目录的main包:
dlv debug(等价于dlv debug --headless=false) - 附加到已运行进程(比如服务已启动):
dlv attach <pid></pid>,但要求进程是用go build -gcflags="all=-N -l"编译的,否则变量和行号信息会被优化掉,断点可能不生效
怎么设断点、跳过和继续执行
进dlv交互界面后,断点不是靠IDE点一下就完事的,得手动输命令。最常用的是break(可简写为b),但它对路径敏感:必须用相对于当前工作目录的相对路径,不能用GOPATH或模块路径。
常见断点写法:
立即学习“go语言免费学习笔记(深入)”;
-
b main.go:12—— 在当前目录下main.go第12行设断点 -
b mypkg.MyFunc—— 在函数入口设断点,支持包名限定,如http.(*ServeMux).ServeHTTP -
b -l—— 列出所有已设断点;clear main.go:12—— 清除指定位置断点
断点命中后,n(next)是单步执行(不进函数),s(step)是单步进入函数,c(continue)是继续运行直到下一个断点。注意:n在for循环里容易“跳过”迭代,真要看每次循环,得用s或在循环体内设断点。
怎么查看变量值和调用栈
变量查看不能靠鼠标悬停,得打命令。print(简写p)是最直接的方式,但要注意它的求值上下文是当前栈帧,不是全局作用域。
典型操作:
-
p err—— 打印变量err的值;p *ptr—— 解引用指针 -
p len(mySlice)—— 支持简单表达式,但不支持函数调用(比如p fmt.Sprintf(...)会报错) -
locals—— 列出当前函数所有局部变量(含未初始化的,显示为nil或零值) -
stack(简写bt) —— 查看完整调用栈,每行带goroutine ID和源码位置;goroutines—— 列出所有goroutine,goroutine 12 bt可切换并查看指定goroutine的栈
有个坑:如果变量是接口类型(比如io.Reader),p只显示接口头,看不到底层具体类型。得用p *(**runtime.iface)(unsafe.Pointer(&v))这种绕过方式,但通常更简单的是在代码里加fmt.Printf("%#v", v)辅助判断。
为什么调试时看不到变量或断点不触发
这不是Delve的问题,大概率是编译选项或代码结构导致的。两个最常见原因:
- 用了默认
go build,没加-gcflags="all=-N -l":-N禁用变量内联,-l禁用函数内联,缺一不可。否则Delve找不到变量符号,locals为空,p报could not find symbol - 断点设在被编译器优化掉的代码上:比如空的
if false { ... }块,或者defer里调用的函数如果没副作用,也可能被删。用go build -gcflags="-S"看汇编能确认是否还在
还有个小细节:Delve对Go版本有兼容性要求。比如Go 1.22新引入的go:build约束处理变动,旧版dlv(v1.21.x)可能无法正确解析模块路径。查版本用dlv version,确保它支持你正在用的Go版本。


















