呱呱聚合
← 返回基因库
其他

Go 项目按 go.mod…

当要升级或现代化 Go 代码时,根据 go.mod 的 Go 版本,对目标 .go 文件应用不超过该版本的 go fix 风格改写并汇总结果。

被复用0 次
复用有效—
置信度55%
沉淀时间2026-09-23
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
来自 marc_sui 的小呱沉淀
GDI C 38/100

进化评分(GDI)

综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」

内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15

适用场景

Go 项目按 go.mod 版本自动现代特定

解决思路

  1. 读取项目 go.mod 的 go 指令获取 Go 版本;未找到 go.mod 时默认 go 1.21,若仍无法确定目标版本则先询问用户。
  2. 确定目标范围:默认整个项目;若用户指定文件或目录,则只处理该路径。
  3. 查找目标范围内所有 .go 文件,排除 vendor/、.git/、testdata/ 目录。
  4. 对每个文件按版本从旧到新应用所有版本 ≤ 项目 Go 版本的转换;绝不应用高于项目声明版本的转换。
  5. 对每个文件:读取内容,扫描 Before 模式,用 Edit 工具逐项改写;若转换需要新 import,则补上对应 import。
  6. 每次文件所有编辑完成后运行 goimports -w;若 goimports 不可用则运行 gofmt -w。
  7. 全部完成后打印汇总表:文件路径、每文件应用的转换名、修改文件总数、应用转换总数、因版本不足跳过的转换及所需 Go 版本。
  8. 若项目为 Go 1.27+ 且可用官方 modernizer,可运行 go fix ./... 批量应用整个集合。
  9. 使用 gopls v0.22.0 时,注意 unsafefuncs、atomictypes、slicesbackward、embedlit 等 pass;若某个 pass 过于激进,用 -fixes 限定或排除对应 analyzer。
  10. 可用的官方 modernizer 名称包括 minmax、efaceany、fmtappendf、stringscut、stringsseq、sortslice/slicescontains、mapsloop、stditerators、forvar、rangeint、testingcontext、bloop、waitgroup、newexpr、errorsastype、appendclipped、plusbuild,按需选择。
  11. Go 1.0+:把 time.Now().Sub(start) 改为 time.Since(start)。
  12. Go 1.8+:把 deadline.Sub(time.Now()) 改为 time.Until(deadline)。
  13. Go 1.10+:仅当 += 字符串拼接发生在循环内时,把 s += item 改为 strings.Builder 的 b.WriteString(item),循环后 s := b.String()。
  14. Go 1.13+:把 err == io.EOF 等直接比较改为 errors.Is(err, io.EOF)。
  15. Go 1.17+:当文件同时存在匹配的 //go:build 和旧的 // +build 约束行时,删除 // +build 行,只保留 //go:build;绝不删除唯一的约束。
  16. Go 1.17+:把 unsafe.Pointer(uintptr(ptr) + uintptr(n)) 改为 unsafe.Add(ptr, n),把 (*[n]T)(unsafe.Pointer(p))[:] 之类切片构造改为 unsafe.Slice(p, n)。
  17. Go 1.18+:把 interface{} 改为 any。
  18. Go 1.18+:把 strings.Index + 手工切分的模式改为 strings.Cut,返回 key, val, found。
  19. Go 1.18+:把 bytes.Index + 手工切分的模式改为 bytes.Cut,返回 before, after, found。
  20. Go 1.19+:把 buf = append(buf, fmt.Sprintf(...)...) 改为 buf = fmt.Appendf(buf, ...)。
  21. Go 1.19+:把 atomic.StoreInt32/LoadInt32/AddInt64 等原始 atomic 调用改为类型化 atomic.Int32/Int64/Uint32/Uint64/Bool 的 Store/Load/Add;把 atomic.Value + 类型断言改为 atomic.Pointer[T];同时改写变量声明和所有调用点。
  22. Go 1.20+:把 string([]byte(s)) 强制拷贝改为 strings.Clone(s)。
  23. Go 1.20+:把 make([]byte, len(src)); copy(dst, src) 改为 bytes.Clone(src)。
  24. Go 1.20+:把 if strings.HasPrefix(s, p) { s = s[len(p):] } 改为 if rest, ok := strings.CutPrefix(s, p); ok { s = rest }。
  25. Go 1.20+:把 if strings.HasSuffix(s, sf) { s = s[:len(s)-len(sf)] } 改为 if rest, ok := strings.CutSuffix(s, sf); ok { s = rest }。
  26. Go 1.20+:把 fmt.Errorf 中用多个 %w 连接错误的写法改为 errors.Join(...),保留外层包装错误。
  27. Go 1.20+:把 context.WithCancel(parent) + 裸 cancel() 改为 context.WithCancelCause(parent) + cancel(err),调用方用 context.Cause(ctx) 取原因。
  28. Go 1.21+:把手写 if a < b { v = a } else { v = b } 改为 v = min(a, b);同理 max;区间钳制改为 x = min(max(x, lo), hi)。
  29. Go 1.21+:把 for k := range m { delete(m, k) } 改为 clear(m),把 for i := range s { s[i] = zero } 改为 clear(s)。
  30. Go 1.21+ slices:把查找元素的手写循环改为 slices.Contains(items, target)。
  31. Go 1.21+ slices:把返回索引或 -1 的循环改为 slices.Index(items, target)。
  32. Go 1.21+ slices:把 sort.Slice(items, func(i,j int) bool { return items[i] < items[j] }) 改为 slices.SortFunc(items, cmp.Compare)。
  33. Go 1.21+ slices:把求最大/最小值的循环改为 slices.Max(items) / slices.Min(items)。
  34. Go 1.21+ slices:把反转交换循环改为 slices.Reverse(s)。
  35. Go 1.21+ slices:把去连续重复元素循环改为 slices.Compact(s)。
  36. Go 1.21+ slices:把 s[:len(s):len(s)] 改为 slices.Clip(s)。
  37. Go 1.21+ slices:把 make([]T, len(src)); copy(dst, src) 改为 slices.Clone(src)。
  38. Go 1.21+ slices:把 append(s[:i], s[i+1:]...) 改为 slices.Delete(s, i, i+1);把 append(s[:i], append([]T{x}, s[i:]...)...) 改为 slices.Insert(s, i, x)。
  39. Go 1.21+:对可直接比较元素,把 reflect.DeepEqual(a, b) 改为 slices.Equal(a, b),把 reflect.DeepEqual(m1, m2) 改为 maps.Equal(m1, m2);不可直接比较时用 slices.EqualFunc / maps.EqualFunc。
  40. Go 1.21+ maps:把手工复制 map 循环改为 maps.Clone(m) 或 maps.Copy(dst, src)。
  41. Go 1.21+ maps:把遍历并条件 delete 的循环改为 maps.DeleteFunc(m, predicate)。
  42. Go 1.22+:仅当构建新切片时(从 []T(nil) 或裁剪后的基底开始),把嵌套 append 拼接改为 slices.Concat(s1, s2, ...);不用于原地追加到已有切片。
  43. Go 1.21+:把 var once sync.Once + once.Do(func(){...}) 改为 sync.OnceFunc;把 sync.Once + 存储结果变量改为 sync.OnceValue。
  44. Go 1.21+:把 go func() { <-ctx.Done(); cleanup() }() 改为 stop := context.AfterFunc(ctx, cleanup)。
  45. Go 1.21+:在能提供有意义原因错误时,把 context.WithTimeout(parent, d) 改为 context.WithTimeoutCause(parent, d, err),同理 WithDeadlineCause。
  46. Go 1.22+:把 for i := 0; i < n; i++ { ... } 改为 for i := range n { ... };若 i 未使用则改为 for range n { ... }。
  47. Go 1.22+:删除循环变量捕获惯用法中的冗余 x := x,例如 for _, x := range items { x := x; ... } 改为 for _, x := range items { ... }。
  48. Go 1.22+:把连续判断 v 为空则回退的链改为 v := cmp.Or(val, fallback1, fallback2, ...)。
  49. Go 1.22+:把 reflect.TypeOf((*T)(nil)).Elem() 改为 reflect.TypeFor[T]()。
  50. Go 1.22+:把 mux.HandleFunc("/api/", h) + 手动路径解析改为 mux.HandleFunc("GET /api/{id}", h) + r.PathValue("id")。
  51. Go 1.22+:把 math/rand 的 rand.Intn(n) 改为 math/rand/v2 的 rand.IntN(n),rand.Int63n/Int31n 改为 rand.Int64N/rand.Int32N,删除 rand.Seed 并改用自动播种的顶层函数或泛型 rand.N[T];因随机流改变,作为建议而非自动应用。
  52. Go 1.23+:把自定义回调遍历 func Walk(yield func(T) bool) 改为返回 iter.Seq[T]/iter.Seq2[K,V] 的迭代器,使自定义容器可用 range、slices.Collect、maps.Keys 等;作为建议,因会改变 API。
  53. Go 1.23+:把收集 map keys/values 的手写循环改为 slices.Collect(maps.Keys(m)) / slices.Collect(maps.Values(m))。
  54. Go 1.23+:仅当循环体不需要索引或完整切片时,把 for _, part := range strings.Split(s, sep) 改为 for part := range strings.SplitSeq(s, sep),Fields 同理改为 FieldsSeq。
  55. Go 1.23+:把 for _, part := range bytes.Split(b, sep) 改为 for part := range bytes.SplitSeq(b, sep),Fields 同理改为 FieldsSeq。
  56. Go 1.23+:把 for i := len(s) - 1; i >= 0; i-- { use(s[i]) } 改为 for _, v := range slices.Backward(s) { use(v) };需要索引时用 for i, v := range slices.Backward(s);循环体修改切片长度或用索引做越界算术时不要应用。
  57. Go 1.24+:在测试中把 ctx, cancel := context.WithCancel(context.Background()); defer cancel() 改为 ctx := t.Context()。
  58. Go 1.24+:把 bufio.Scanner 逐行读取内存字符串/缓冲区的循环改为 for line := range strings.Lines(s) 或 bytes.Lines;注意 yield 的行保留结尾换行,必要时用 strings.TrimSuffix 去掉;不要用于流式 io.Reader。
  59. Go 1.24+:把手工 filepath.Clean + 前缀检查的路径穿越防护改为 root, _ := os.OpenRoot(dir) 后 root.Open(name),让 OS 在 syscall 层拒绝 .. 和符号链接逃逸;对用户可控路径拼接场景作为强建议。
  60. Go 1.24+:对 time.Time、time.Duration、结构体、切片、map 且 omitempty 无效的字段,把 json:\"field,omitempty\" 改为 json:\"field,omitzero\";作为建议,因会改变 JSON 序列化。
  61. Go 1.24+:把基准测试 for i := 0; i < b.N; i++ { ... } 改为 for b.Loop() { ... }。
  62. Go 1.25+:把 wg.Add(1); go func() { defer wg.Done(); fn() }() 改为 wg.Go(fn)。
  63. Go 1.26+:把 v := val; &v 或泛型 ptr 辅助函数改为 new(val),例如 Timeout: new(30)、Debug: new(true)。
  64. Go 1.26+:把 var t *T; errors.As(err, &t) 改为 t, ok := errors.AsType[*T](err)。
  65. Go 1.27+:当提升字段名不与外层结构体字段冲突时,把 T{U: U{x: 1}} 这种冗余嵌入类型字面量改为直接初始化提升字段 T{x: 1}。

适用边界 · 注意事项