代码 gopls v0.24.0:交互式重构走 LSP 扩展,ptrtoerror 抓 E 与 *E 混用

2026-10-18 21:01:37

gopls v0.24.0:交互式重构走 LSP 扩展,ptrtoerror 抓 E 与 *E 混用

gopls v0.24.0(2026 年 10 月)发布。这个版本支持 LSP 3.18,改进了 Go assembly 文件的 Hover、DocumentHighlight、References 和「零配置」(自动选择合适的构建标签),分析侧换用 staticcheck v0.8.1,并新增 ptrtoerror 分析器。交互式重构由 Go 团队设计的 LSP 扩展承载,gopls 与 VS Code Go 扩展已提供可用支持。

配置变化

memoryLimit 允许客户端通过 runtime/debug.SetMemoryLimit 给 gopls 进程设置软内存上限。该特性是实验性的:可以用更多 CPU 换取更低的稳态内存占用,但设得太低会引发 GC thrashing。

语义 token 能力开始被强制校验。 gopls 现在会检查 SemanticTokensClientCapabilities 中的 TokenTypes 和 TokenModifiers 字段,返回的语义 token 类型与修饰符被限制在这两个列表内,因此客户端需要完整列出自己的语义 token 能力。用户仍可通过 UI 设置 semanticTokenTypes 和 semanticTokenModifiers 进一步收窄列表。

零配置覆盖 assembly 文件。 gopls 的「零配置」行为会自动为打开的 Go 源文件选择合适的 OS/ARCH 组合来构建,现在这一行为同样会考虑已打开的 Go assembly 文件。

被动特性:assembly 文件中的 Hover

在 Go assembly 文件中悬停到某个符号上,会显示其 Go 声明的签名和文档注释。

编辑特性

type switch 的 case / default 悬停。 悬停在 type switch 的 case 或 default 关键字上,会显示该 case 处理的类型中,与 switch 操作数接口类型同包声明的那些类型。因此悬停 default 可能暴露出一个本想穷举的 switch 里未处理的类型。对于非接口类型的 case,只有在该 case 因前面的分支而不可达时才会显示信息。

包名上的文档链接。 悬停在包名的定义、引用或 import 上时,文档链接会渲染为指向代码定义或 pkgsite 的链接。例如注释 // xyz uses [TestA.FieldOne] 中的 [TestA.FieldOne]。

assembly 文件中的 documentHighlight。 光标下的符号、label 或机器寄存器在所属 TEXT 函数内的所有出现都会被高亮,其中定义归类为写、引用归类为读。

assembly 文件中的 references。 现在支持没有对应 Go 声明的控制 label 和符号。

补全的 labelDetails。 对声明了 completionItem.labelDetailsSupport 的客户端,补全项会返回 labelDetails:detail 存放该项的签名或类型,description 存放接受该项后会被加入文件的 import path。

分析特性

gopls 现在使用 staticcheck v0.8.1。

ptrtoerror 分析器

新分析器报告命名类型 E 与其指针类型 *E 作为 error 使用不一致的情况。

声明 func (E) Error() string 会让 E 和 *E 都实现 error,于是同一个包可能在一处返回 E{...}、另一处返回 &E{...}。这是潜在的 bug:客户端用类型断言或 errors.Is 检查错误时必须二选一,而当错误由另一种形式创建时,检查会静默失败。

分析器报告三类问题:

  • 在声明 E 的包内,E 和 *E 的值都被转换为 error。分析器报告类型声明以及每一次转换。
  • 声明包一致地使用一种形式,但另一个包把另一种形式转换为 error。分析器报告另一个包中的转换,并指出声明包使用偏好形式的位置。
  • E 和 *E 都实现 error,但声明包没有把任何一方转换为 error,意图不明确。分析器提供两个替代修复来显式声明预期形式:
var _ error = *new(E)
var _ error = (*E)(nil)

slicesclip modernizer

建议把完整切片表达式 x[:len(x):len(x)] 替换为 Go 1.21 引入的 slices.Clip(x)。

importcomment modernizer

删除指定规范 import 路径的过时注释,例如 package foo // import "example.com/foo"。go 命令只在 GOPATH 模式下强制这些注释,模块模式下会被忽略。

reflecttypeassert modernizer

建议把 x, ok := v.Interface().(T) 替换为 Go 1.25 引入的 x, ok := reflect.TypeAssert[T](v),后者避免分配中间接口值。单值断言不提供修复:它在失败时会 panic,而 reflect.TypeAssert 不会。

stringintconv 适配 Go 1.28

Go 1.28 拒绝 string(x) 形式的转换,其中 x 是 byte 或 rune 之外的整数(#3939)。分析器的第一个修复精确保留现有行为,使用 string(rune(x));对宽于 32 位的类型改用 fmt.Sprintf("%c", x),因为截断到 rune 可能让无效码点变成有效码点。第二个修复 fmt.Sprintf("%d", x) 把数字按十进制格式化。

「Implement interface」支持泛型接口

交互式代码动作「Add methods to implement an interface…」现在支持泛型接口。当选中的接口带有类型参数时,gopls 会为每个类型参数提示输入类型实参,并生成带实例化方法签名的方法 stub。

交互式重构(Go blog,2026-10-16)

Go 为 gopls 和 VS Code 扩展加入交互式重构,开发者可以通过编辑器对话框引导代码变换。可用的重构包括自定义 struct tag、生成接口方法,移动声明处于预览阶段。gopls v0.24.0 与 Go extension for VS Code v0.56.0 提供可用支持。

LSP 目前没有让服务器向客户端提问的机制。Go 团队与 Dart IDE 团队合作,为 LSP 设计了一个扩展来支持交互式对话框,并正在推动其被 LSP 标准采纳。

Add struct tags(gopls v0.23.0)。 光标放在 struct 定义上,执行「Add struct tags」动作,对话框预填 json,可自定义组合(json,yaml,db);第二个对话框选择命名约定(camelCase、snake_case、PascalCase),gopls 随后在整个类型上生成 tag。

实现接口。 光标放在具体类型上,执行「Add methods to X to implement an interface…」,文本框会动态自动补全工作区和标准库中的接口名(如 maphash.Hasher);有类型参数时逐个提示,生成带接收者名称和实例化签名的方法 stub。

移动声明(预览)。 光标放在顶层声明上,执行「Move declaration X」,用文件选择器指定目标 .go 文件;声明会连同依赖声明(未导出 helper、方法)一起移动,引用被更新,两个文件的 import 都会被清理。该功能计划在下一个版本发布。

「Slay the dragon」(v0.24.0)。 把光标放在名为 dragonSlayer 的包级变量上会出现一个代码动作,它是多步对话框的演示兼测试用例。

后续方向。 change signature(#38028)、交互式冲突解决,以及代码编辑之外的交互式命令(例如 profiling flags)。

复制全文 生成海报 Go 工具链 静态分析

推荐文章

程序员茄子在线接单