关于 go-idiomatic
Go Idiomatic 为开发者编写或审查代码提供该仓库特有的 Go 约定,并按主题指向详细参考资料和相关 skill。
主要功能
- 01错误处理与日志规则
- 02代码组织约定
- 03函数与命名指引
- 04按主题指向参考资料
- 05Go 工具要求
适用场景
- 01实施 Go 仓库代码变更
- 02审查 Go 代码约定
- 03查找特定 Go 主题的参考资料
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ o-marsters-1997/ my-claude-code --skill go-idiomatic安装后在 Claude Code 中输入/go-idiomatic确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonevals/files/optional-field/go.modevals/files/optional-field/internal/user/user.goevals/files/refactor-store/go.modevals/files/refactor-store/helpers/helpers.goevals/files/refactor-store/store/store.goevals/files/server-settings/go.modevals/files/server-settings/cmd/app/main.goevals/files/server-settings/internal/server/server.goreferences/concurrency.mddatabase.mderrors.mdexec.mdhttp-client.mdlogging.mdmiddleware.mdoptional.mdpatterns.mdsecrets.mdvalue-vs-pointer.md详细介绍
Go 惯用实践
本仓库中 Go 的规则,适用于与通用 Go 实践不同或对其进一步明确的情况。以下规则适用于每项变更;详细说明和示例见参考文档。
查阅位置
继续阅读前,先找到相应的参考文档:
| 如果你正在处理…… | 加载此文档 |
|---|---|
| Goroutine、通道、同步原语、errgroup、泄漏、竞态 | references/concurrency.md |
添加 sentinel 或错误类型、在包之间或转换为 HTTP 响应时转换错误、记录错误来源、在 defer 中清理、panic | references/errors.md |
| HTTP 中间件:请求 Content-Type、CSRF、会话 Cookie 属性 | references/middleware.md |
| 存储会话或重置令牌、重置或更改密码、加密列 | references/secrets.md |
为 main 或组件提供日志记录器、选择日志级别、区分 CLI 输出与日志 | references/logging.md |
| 接口设计、零值、标识符类型、类型化值集合、反模式 | references/patterns.md |
| 编写或审查测试、基准测试、模糊测试、测试数据库 | go-testing 技能 |
可选字段或返回值——何时使用 Option[T] | references/optional.md |
| 指针接收者与值接收者、变更与可选性 | references/value-vs-pointer.md |
为第三方 API 搭建 Go HTTP 客户端、编写 NewXxxClient,或为出站 HTTP 调用附加身份验证 | references/http-client.md |
使用 os/exec 调用 git、gh 或其他 CLI、解析其 --json 输出、在测试中伪造其行为 | references/exec.md |
| 在 SQL 中存储数据:存储包边界、事务、NULL、约束错误、连接池设置 | references/database.md |
为 htmx 渲染 html/template:页面与片段的区分、重定向、HX-* 标头、.tmpl 文件 | htmx-go-templates 技能 |
错误与日志记录
几乎每项变更都会返回或报告错误,因此这些规则适用于所有 Go 工作,而不只是错误处理相关任务:
- 使用
fmt.Errorf("<verb> <noun>: %w", err)包装错误。错误字符串使用小写,不加标点,也不写 "failed to"。 - 每个错误只处理一次:附带上下文后返回,或在调用链顶层记录日志。切勿两者兼做。
- 仅当其他包中的调用方会据此分支处理时,才导出 sentinel。在检测到该条件的位置定义它,并在包边界将依赖项的错误转换为自己的错误。
- 切勿使用
_ =丢弃错误。将清理错误合并到返回的错误中;若没有可返回的对象,则在Warn级别记录。 - 仅因程序员错误才使用
panic:对常量输入使用Must辅助函数,或处理不可能出现的情况。 - 只有错误会在此处停止传播的组件(处理程序、工作进程、长期运行的服务)才应通过构造函数字段注入
*slog.Logger。下层代码应返回错误且不接收日志记录器。main创建唯一的日志记录器;任何代码都不调用log.*、slog.Info或slog.Default()。 - 日志消息必须是常量;可变数据放入 snake_case 键值属性,错误使用
err。切勿记录秘密或个人数据。 - 用户要求的输出应写入注入的
io.Writer,而不是日志记录器。
常规的 return fmt.Errorf(...) 或日志语句只需遵守这些规则。添加 sentinel 或错误类型、将错误转换为 HTTP 响应、包装驱动程序或出站调用错误,或处理清理错误时,加载 references/errors.md;接入日志记录器、选择日志级别或区分 CLI 输出时,加载 references/logging.md。
测试
编写、编辑或审查 _test.go 文件时:加载 go-testing skill,它负责规定 Go 测试的编写方式,包括测试数据库。测试什么(测试类型、每种测试的价值、可复用模式)由仓库提供的 testing-policy 规定。
代码组织
- 应用将
main放在cmd/<app>/main.go中,该文件只负责连接依赖;其他所有内容都放在internal/下。pkg/用于供仓库外导入的库模块;在应用中使用它,意味着提供了一个实际并不存在的公共 API。 - 在含义不同的多个包中,第 三 次重复时再提取共享逻辑,而不是第二次。与某个领域紧密耦合的辅助函数应放在
internal/中,靠近其主要调用方。 - 包名应体现其用途(
stringx、idgen、timeutil)。只有当utils被多个包使用且不导入internal/中的内容时,才允许使用。绝不允许使用helpers和common:总能找到一个更准确的名称。 - 不要使用包级状态,例如在
init()中设置全局*sql.DB。通过构造函数传递依赖。 main只解析一次环境变量,将其放入有类型的配置结构体中,并进行验证;遇到无效值时,应在启动时退出,而不是等到第一个需要该值的请求到来时才退出。构造函数只接收自身使用的字段,而非整个结构体。cmd/以下的代码不得调用os.Getenv。
函数设计
-
参数超过 3–4 个时,将它们归入结构体,或对将来可能扩展的构造函数使用函数选项(
opts ...Option);新增选项向后兼容,新增位置参数则不兼容。 -
复杂参数应先声明为具名局部变量,再传入调用,而不是将构造函数调用嵌套在内联表达式中:
sentAt := time.Now().Add(-24 * time.Hour) priority := Priority(3) client.Send(NewMessage(sender, recipient, sentAt, priority)) -
优先进行守卫检查并提前返回;正常路径应保持在底部,不缩进,且
return后不要接else。使用switch,而不是if/else if链。 -
可变更的对象和可测量的大型结构体使用指针;小型不可变类型使用值。绝不要用
*T表示“可能未设置”;这种情况应使用Option[T]。
命名与注释
函数名应体现其返回值或操作(ParseConfig、IsExpired),布尔值名称应体现谓词(canRetry)。只使用 Go 惯例缩写(ctx、err、id、r、w)。
~/.claude/rules/comments.md 规定哪些内容值得写注释。它是权威规范,本 skill 不会重复或弱化其中的要求。编辑文件前先阅读该文件,并按其原文要求执行,包括行数上限和仅为导出标识符编写文档注释的规则。internal/ 并非公共 API。审查 Go 代码的注释质量时,使用 clean-comments skill。不要要求它匹配文件现有的注释密度。
工具
完成前运行 gofmt、goimports、go vet ./... 和 golangci-lint run。机械规则交由 linter 处理,不要在此重复。对于现有违规,绝不要添加 //nolint:应修复问题,或暂时关闭相关规则,直到问题修复。
另请参阅
| Skill | 适用场景 |
|---|---|
go-testing | 测试编写方式:断言、替身、表格驱动测试、测试数据库 |
tdd | TDD 周期、红绿重构、先编写测试 |
clean-comments | 审查并移除 Go 代码中的解释性注释 |
improve-codebase-architecture | 识别结构性改进和浅层模块 |
simplify | 实现后审查变更代码的质量、复用性和效率 |