mcpField
G
go-modernize

go-modernize

github.com/eduardo-sl开发83146 次安装2 周前更新
代码仓库

关于 go-modernize

面向 Go 项目的渐进式现代化技能,指导代码采用模块 Go 指令所支持的特性,并涵盖升级流程及语言和标准库迁移。

主要功能

  1. 01渐进式现代化工作模式
  2. 02按 Go 版本整理的特性参考
  3. 03官方现代化工具使用指引
  4. 04标准库 API 迁移示例
  5. 05检查变更与版本兼容性

适用场景

  1. 01仅现代化当前正在修改的代码
  2. 02规划 Go 指令版本升级
  3. 03更新弃用或旧式标准库用法
  4. 04对包或模块执行现代化扫描

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-modernize

安装后在 Claude Code 中输入/go-modernize确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
generics.md
go1.27.md
stdlib-migrations.md
version-bump.md

详细介绍

Go 现代化

Go 在不断演进。为 Go 1.16 编写的代码,不应与面向 Go 1.27 的代码相同。逐步进行现代化改造——先更新 go.mod,再采用新的模式。

切勿采用超出 go.mod 中 go 指令版本的功能。应有计划地提高该指令版本,单独提交,并且仅提高到项目的 CI 和部署镜像实际运行的版本。

按需加载详细参考资料:

  • references/generics.md — 用类型参数替换 interface{}、约束、泛型容器,以及何时不应使用泛型。
  • references/stdlib-migrations.md — slog、errors.Join、slices/maps 辅助函数、按整数范围迭代和迭代器的迁移前后示例。
  • references/go1.27.md — 泛型方法、CutLast、URL/Values Clone、big.Int.Divide、标准库 uuid、json/v2 语义、synctest 和 httptest 新增内容、工具链变更。
  • references/version-bump.md — 提高 go 指令版本的流程和逐版本检查清单(1.25-1.27),说明可能造成的影响。

仅当以下摘要不足以解答时,才阅读参考文件。

操作模式

  • Inline(默认——开发者正在处理其他事项):仅现代化你已在修改的代码行。其他可改进之处只在结尾提及一次,并说明带来的收益;不要修改无关文件——未经请求的大范围改动会淹没真正的改动。如果建议被拒绝,本次会话中不要再提;如果开发者希望记住这一点,可在项目的 Agent 配置文件(CLAUDE.md、AGENTS.md)中添加一行。
  • Version bump(提高 go 指令版本):即使没有修改源代码,也属于行为变更。在采用任何功能之前,先遵循 references/version-bump.md 中的前提条件和逐版本影响检查清单。
  • Sweep(受托现代化某个包或模块):运行以下流程,并按类别分别提交——go fix 输出、已弃用 API、语言功能、标准库辅助函数、测试——每个类别的构建和测试都必须通过。这些类别彼此独立;如果环境支持并行子 Agent,可为每个类别分配一个任务,并使用单独的分支或工作树。

优先级顺序

时间有限时按以下顺序处理:

  1. 正确性和安全性 — 使用 errors.Is/As 替代 ==,使用 http.NewRequestWithContext,对用户提供的路径使用 os.Root,凡是随机性用于保护某项内容时使用 crypto/rand,用标准库版本替换已弃用的 x/crypto 包。
  2. 可读性 — any、min/max、按整数范围迭代、slices/maps、cmp.Or、sync.OnceValue、wg.Go、errors.AsType。
  3. 渐进式改进 — 迭代器、迁移到 slog 日志记录器、go.mod 工具指令,以及移除标准库现已涵盖功能的依赖项。

现代化流程

  1. 检查 go.mod 中的 go 指令——它限制了可使用的功能。提高该指令版本属于 Version bump 模式,绝不能作为功能变更的附带操作。

  2. 先运行官方现代化工具——它们会自动查找并修复机械式迁移:

    # Go 1.26+ — the modernizers now live in go fix
    go fix ./...
    
    # Go 1.25 and earlier, or a modernizer newer than your toolchain
    go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...
    

    两者都会原地改写源代码。运行前先提交,并检查差异。如果这两个命令都不可用,请手动应用下表中的改动。

  3. 扫描下表,查找分析器未涵盖、需要判断的迁移(泛型、迭代器、替换日志记录器),并逐项应用。

  4. 每组改动完成后,运行 go build ./... 和测试套件。

按 Go 版本划分的功能表

Go 版本功能操作
1.13+errors.Is, errors.As替换 == 错误比较
1.13+http.NewRequestWithContext替换 http.NewRequest
1.16+embed替换 go-bindata / packr
1.18+泛型替换 interface{} 工具函数
1.20+errors.Join替换手动累积错误
1.21+log/slog替换 log,以实现结构化日志记录
1.21+slices, maps替换手写的切片 / 映射工具函数
1.21+min, max 内置函数替换 math.Min/math.Max(仅支持 float64)
1.21+sync.OnceValue, sync.OnceFunc替换 sync.Once + 包级变量组合
1.22+遍历整数替换 for i := 0; i < n; i++
1.22+每次迭代独立的循环变量删除 v := v 影子副本(仅当 go.mod 声明版本为 1.22+ 时)
1.22+math/rand/v2替换 math/rand;删除 rand.Seed
1.22+cmp.Or替换“首个非零值”if 链
1.22+ServeMux 方法 + 通配符模式替换仅用于 GET /users/{id} 的路由器依赖
1.23+遍历函数替换基于回调的迭代
1.23+unique.Make替换手写的字符串驻留实现
1.24+for b.Loop()替换基准测试中的 for range b.N
1.24+t.Context()替换测试中的 context.Background()
1.24+os.Root替换手动路径遍历检查
1.24+go.mod tool 指令替换 tools.go 空导入文件
1.24+runtime.AddCleanup替换 runtime.SetFinalizer
1.24+omitzero 结构体标签当 Go 零值(例如 time.Time{})必须省略时,替换 omitempty
1.24+strings.SplitSeq, strings.Lines, FieldsSeq当切片仅用于遍历时,替换 Split
1.24+crypto/sha3, crypto/hkdf, crypto/pbkdf2替换 golang.org/x/crypto 中的对应实现
1.24+crypto/rand.Text替换手写的随机令牌编码器
1.25+testing/synctest替换并发测试中的 time.Sleep
1.25+sync.WaitGroup.Go替换 wg.Add(1) + go func(){defer wg.Done()}
1.25+reflect.TypeAssert替换 v.Interface().(T)(不分配内存)
1.25+感知容器的 GOMAXPROCS移除 go.uber.org/automaxprocs
1.26+errors.AsType替换 errors.As 和已声明的目标变量
1.26+slog.NewMultiHandler替换手写的扇出处理器
1.26+new(expr)替换取地址的临时变量
1.26+httputil.ReverseProxy.Rewrite替换已弃用且不安全的 Director 钩子
1.27+泛型方法替换属于某个类型的包级泛型辅助函数(接口必须公开这些方法时除外)
1.27+将提升字段用作字面量键替换 Outer{Inner: Inner{ID: x}} 嵌套写法
1.27+strings.CutLast, bytes.CutLast替换 LastIndex + 切片操作
1.27+url.URL.Clone, url.Values.Clone替换手写的深拷贝
1.27+big.Int.Divide替换 QuoRem + 符号修正
1.27+标准库 uuid对于 v4/v7 ID,替换 google/uuid
1.27+encoding/json/v2按调用点采用——语义更严格,参见参考文档
1.27+synctest.Sleep, httptest.NewTestServer替换 time.Sleep+Wait 和依赖套接字的测试服务器
1.27+testing/cryptotest.SetGlobalRandom替换测试中的 tls.Config.Rand

迁移示例

上表每一行的迁移前后示例均见 references/stdlib-migrations.md(标准库和语言功能)以及 references/generics.md(类型参数)。测试专用迁移—— t.Context()、b.Loop()、synctest——由 go-test-quality 技能负责。

验证清单

  1. go.mod 中的版本与代码库中使用的功能相符
  2. 使用 any 或类型参数会更清晰时,不使用 interface{}
  3. 使用 log/slog 进行结构化日志记录,而非 log.Printf
  4. 使用 errors.Join,而非手动拼接错误字符串
  5. 使用 slices.Contains、slices.SortFunc、maps.Clone 替代手写循环
  6. 适用时使用整数范围循环(for i := range n)
  7. 使用 http.NewRequestWithContext,而非 http.NewRequest
  8. 不使用 sort.Slice——使用 slices.SortFunc 和 cmp.Compare
  9. 使用泛型实现类型安全的容器和实用工具,但不要在简单场景中过度使用
  10. 评估第三方依赖是否有近期 Go 版本新增的标准库替代方案
  11. 使用 sync.WaitGroup.Go,而非手动调用 Add/Done(Go 1.25+)
  12. 测试使用 t.Context() 和 for b.Loop()(Go 1.24+)
  13. 使用 go.mod 的 tool 指令替代 tools.go(Go 1.24+)

评论

支持 Markdown