mcpField
W
writing-go

writing-go

github.com/julianobarbosa开发14109 次安装2 天前更新
代码仓库

关于 writing-go

writing-go 是面向 Go 开发者的技能资料,介绍标准库优先、组合设计和清晰错误处理等原则。内容包括实用代码模式、Go 1.25 特性、工具和常见陷阱。

主要功能

  1. 01错误处理与上下文包装
  2. 02选项模式和表驱动测试示例
  3. 03Go 1.25 特性概览
  4. 04构建、测试与 lint 工具
  5. 05并发和标准库常见陷阱

适用场景

  1. 01制定 Go 项目的开发规范
  2. 02为函数和服务设计错误处理
  3. 03编写表驱动测试并检查并发代码

安装

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

$npx skills add https://github.com/julianobarbosa/claude-code-skills --skill writing-go

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

包含的文件

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

CLI.md
PATTERNS.md
TESTING.md

详细介绍

Go 开发(1.25+)

核心原则

  • 标准库优先:只有在有充分理由时才使用外部依赖
  • 具体类型:在使用方定义接口,返回结构体
  • 组合:始终优先于继承
  • 快速失败:提供清晰且包含上下文的错误
  • 简单:通常最直观的解决方案就是正确的方案

快速模式

错误处理
if err := doThing(); err != nil {
    return fmt.Errorf("do thing: %w", err)
}
带选项的结构体
type Server struct {
    addr    string
    timeout time.Duration
}

func NewServer(addr string, opts ...Option) *Server {
    s := &Server{addr: addr, timeout: 30 * time.Second}
    for _, opt := range opts {
        opt(s)
    }
    return s
}
表驱动测试
tests := []struct {
    name    string
    input   string
    want    string
    wantErr bool
}{
    {"valid", "hello", "HELLO", false},
    {"empty", "", "", true},
}
for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
        got, err := Process(tt.input)
        if tt.wantErr {
            require.Error(t, err)
            return
        }
        require.NoError(t, err)
        assert.Equal(t, tt.want, got)
    })
}

Go 1.25 特性

  • testing/synctest:使用模拟时钟进行确定性的并发测试
  • encoding/json/v2:实验性功能,速度快 3–10 倍(GOEXPERIMENT=jsonv2)
  • runtime/trace.FlightRecorder:按需捕获生产环境跟踪信息
  • 感知容器的 GOMAXPROCS:自动检测 cgroup 限制
  • GreenTea GC:实验性功能,可降低延迟(GOEXPERIMENT=greenteagc)

参考资料

工具

go build ./...           # Build
go test -race ./...      # Test with race detector
golangci-lint run        # Lint
mockery --all            # Generate mocks

注意事项

  • 向 nil 通道发送或从中接收会永远阻塞;从已关闭的通道接收会立即返回零值 — 在 select 中,nil 通道对应的分支会被禁用。这种模式很有用,但也容易无意中触发。
  • defer 会在调用时而非执行时捕获参数 — defer fmt.Println(time.Now()) 捕获的是此刻的时间,而不是延迟执行时的时间。
  • Go 1.22 之前,for 循环中的闭包会在所有迭代中捕获同一个变量 — 这就是循环中启动 goroutine 时的常见问题。Go 1.22 更改了语义;在混合版本代码中,沿用旧习惯会造成微妙的错误。
  • errors.Is 会遍历 Unwrap() 链,但如果被包装的错误本身实现了 Is(target error) bool,则会优先调用自定义的 Is 方法,而不遍历链 — 从 xerrors 迁移时,这一点容易令人困惑。
  • sync.Pool 中的项可能会在 Get 和下一次 Put 之间被 GC 回收 — 切勿依赖 Pool 保留状态。

评论

支持 Markdown