重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
npx skills add https://github.com/samber/cc-skills-golang --skill golang-naming社区默认。 明确覆盖
samber/cc-skills-golang@golang-naming技能的公司技能优先。
Go 倾向于简短、可读的名称。大小写控制可见性——大写表示导出,小写表示未导出。所有标识符必须使用 MixedCaps,绝对不要使用下划线。
"清晰胜于巧妙。" — Go 箴言
"设计架构,命名组件,记录细节。" — Go 箴言
要忽略某条规则,只需在代码中添加注释。
| 元素 | 约定 | 示例 |
|---|---|---|
| 包 | 小写,单个单词 | json, http, tabwriter |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 文件 | 小写,允许下划线 | user_handler.go |
| 导出名称 | 大驼峰式 | ReadAll, HTTPClient |
| 未导出名称 | 小驼峰式 | parseToken, userCount |
| 接口 | 方法名 + -er | Reader, Closer, Stringer |
| 结构体 | 大驼峰式名词 | Request, FileHeader |
| 常量 | 大驼峰式(非全大写) | MaxRetries, defaultTimeout |
| 接收器 | 1-2 个字母的缩写 | func (s *Server), func (b *Buffer) |
| 错误变量 | Err 前缀 | ErrNotFound, ErrTimeout |
| 错误类型 | Error 后缀 | PathError, SyntaxError |
| 构造函数 | New(单一类型)或 NewTypeName(多类型) | ring.New, http.NewRequest |
| 布尔字段 | 字段和方法使用 is、has、can 前缀 | isReady, IsConnected() |
| 测试函数 | Test + 函数名 | TestParseToken |
| 首字母缩写词 | 全大写或全小写 | URL, HTTPServer, xmlParser |
| 变体:上下文 | WithContext 后缀 | FetchWithContext, QueryContext |
| 变体:原地操作 | In 后缀 | SortIn(), ReverseIn() |
| 变体:错误 | Must 前缀 | MustParse(), MustLoadConfig() |
| 选项函数 | With + 字段名 | WithPort(), WithLogger() |
| 枚举(iota) | 类型名前缀,零值 = 未知 | StatusUnknown 为 0,StatusReady |
| 命名返回值 | 描述性的,仅用于文档 | (n int, err error) |
| 错误字符串 | 全小写(包括首字母缩写词),无标点 | "image: unknown format", "invalid id" |
| 导入别名 | 简短,仅在冲突时使用 | mrand "math/rand", pb "app/proto" |
| 格式化函数 | f 后缀 | Errorf, Wrapf, Logf |
| 测试表字段 | got/expected 前缀 | input string, expected int |
所有 Go 标识符必须使用 MixedCaps(或 mixedCaps)。标识符中绝对不要使用下划线——唯一的例外是测试函数子用例(TestFoo_InvalidInput)、生成的代码以及 OS/cgo 互操作。这是承载性的,而非装饰性的——Go 的导出机制依赖于大小写,并且工具链假定全程使用 MixedCaps。
// ✓ 正确
MaxPacketSize
userCount
parseHTTPResponse
// ✗ 错误——这些约定与 Go 的导出机制和工具链预期相冲突
MAX_PACKET_SIZE // C/Python 风格
max_packet_size // snake_case
kMaxBufferSize // 匈牙利命名法
Go 的调用点总是包含包名,因此在标识符中重复它是在浪费读者的时间——http.HTTPClient 迫使读者解析两次 "HTTP"。名称不得重复包名、类型名或周围上下文中已存在的信息。
// 正确——调用点简洁
http.Client // 而不是 http.HTTPClient
json.Decoder // 而不是 json.JSONDecoder
user.New() // 而不是 user.NewUser()
config.Parse() // 而不是 config.ParseConfig()
// 在包 sqldb 中:
type Connection struct{} // 而不是 DBConnection —— "db" 已在包名中
// 避免重复适用于所有导出的类型,不仅仅是主要结构体:
// 在包 dbpool 中:
type Pool struct{} // 而不是 DBPool
type Status struct{} // 而不是 PoolStatus —— 调用者写 dbpool.Status
type Option func(*Pool) // 而不是 PoolOption
这些约定是正确的但不明显——它们是命名错误最常见的来源:
构造函数命名: 当一个包导出一个单一的主要类型时,构造函数是 New(),而不是 NewTypeName()。这避免了重复——调用者写 apiclient.New() 而不是 apiclient.NewClient()。仅当包有多个可构造类型时才使用 NewTypeName()(如 http.NewRequest, http.NewServeMux)。
布尔结构体字段: 未导出的布尔字段必须使用 is/has/can 前缀——isConnected, hasPermission,而不是裸的 connected 或 permission。导出的 getter 保留前缀:IsConnected() bool。这读起来自然像一个问题,并将布尔类型与其他类型区分开。
错误字符串完全小写——包括首字母缩写词。 写 "invalid message id" 而不是 "invalid message ID",因为错误字符串经常与其他上下文连接(fmt.Errorf("parsing token: %w", err)),混合大小写在句子中间看起来不对。哨兵错误应包含包名作为前缀:errors.New("apiclient: not found")。
枚举零值: 总是在 iota 位置 0 处放置一个显式的 Unknown/Invalid 哨兵。var s Status 会默默地变为 0——如果这映射到一个真实状态如 StatusReady,代码可能会表现得好像状态是被故意选择的,而实际上并非如此。
子测试名称: t.Run() 中表驱动测试用例的名称应该是全小写的描述性短语:"valid id", "empty input"——而不是 "valid ID" 或 "Valid Input"。
有关完整规则、示例和原理,请参阅:
包、文件与导入别名 — 包命名(单个单词、小写、无复数)、文件命名约定、导入别名模式(仅在冲突时使用以避免认知负担)以及目录结构。
变量、布尔值、接收器与首字母缩写词 — 基于作用域的命名(长度匹配作用域:i 用于 3 行循环,较长名称用于包级)、单字母接收器约定(s 代表 Server)、首字母缩写词大小写(URL 而不是 Url,HTTPServer 而不是 HttpServer)以及布尔命名模式(isReady, hasPrefix)。
函数、方法与选项 — Getter/setter 模式(Go 省略 Get 所以 user.Name() 读起来自然)、构造函数约定(New 或 NewTypeName)、命名返回值(仅用于文档)、格式化函数后缀(Errorf, Wrapf)以及函数式选项(WithPort, WithLogger)。
类型、常量与错误 — 接口命名(Reader, Closer 后缀 -er)、结构体命名(名词,MixedCaps)、常量(MixedCaps,非全大写)、枚举(类型名前缀如 StatusReady)、哨兵错误(ErrNotFound 变量)、错误类型(PathError 后缀)以及错误消息约定(小写,无标点)。
测试命名 — 测试函数命名(TestFunctionName)、表驱动测试字段约定(input, expected)、测试辅助函数命名以及子用例命名模式。
| 错误 | 修正 |
|---|---|
ALL_CAPS 常量 | Go 保留大小写用于可见性,而非强调——使用 MixedCaps(MaxRetries) |
GetName() getter | Go 省略 Get,因为 user.Name() 在调用点读起来自然。但 Is/Has/Can 前缀保留用于布尔谓词:IsHealthy() bool 而不是 Healthy() bool |
Url, Http, Json 首字母缩写词 | 混合大小写的首字母缩写词会产生歧义(HttpsUrl —— 是 Https+Url 吗?)。使用全大写或全小写 |
this 或 self 接收器 | Go 方法被频繁调用——使用 1-2 个字母的缩写(s 代表 Server)以减少视觉噪音 |
util, helper 包 | 这些名称没有说明内容——使用描述抽象的具体名称 |
http.HTTPClient 重复 | 包名总是出现在调用点——http.Client 避免读取两次 "HTTP" |
user.NewUser() 构造函数 | 单一主要类型使用 New()——user.New() 避免重复类型名 |
connected bool 字段 | 裸形容词有歧义——使用 isConnected 使该字段读起来像一个真/假问题 |
"invalid message ID" 错误 | 错误字符串必须完全小写,包括首字母缩写词——"invalid message id" |
StatusReady 在 iota 0 | 零值应该是一个哨兵——StatusUnknown 在 0 处可以捕获未初始化的值 |
"not found" 错误字符串 | 哨兵错误应包含包名——"mypackage: not found" 标识来源 |
userSlice 类型名包含类型 | 类型编码实现细节——users 描述它包含什么,而不是如何包含 |
| 不一致的接收器名称 | 在同一类型的不同方法间切换名称会混淆读者——一致地使用一个名称 |
snake_case 标识符 | 下划线与 Go 的 MixedCaps 约定和工具链预期冲突——使用 mixedCaps |
| 短作用域使用长名称 | 名称长度应与作用域匹配——i 对于 3 行循环没问题,userIndex 是噪音 |
| 按值命名常量 | 值会变,角色不会——DefaultPort 在端口更改后仍有效,Port8080 则不行 |
FetchCtx() 上下文变体 | WithContext 是标准的 Go 后缀——FetchWithContext() 是立即可识别的 |
sort() 原地操作但没有 In | 读者假定函数返回新值。SortIn() 表示是原地修改 |
parse() 在错误时 panic | MustParse() 警告调用者失败会 panic——意外情况应体现在名称中 |
混合使用 With*, Set*, Use* | 整个代码库的一致性——With* 是 Go 的函数式选项约定 |
| 复数包名 | Go 约定是单数(net/url 而不是 net/urls)——保持导入路径一致 |
Wrapf 没有 f 后缀 | f 后缀表示格式化字符串语义——Wrapf, Errorf 告诉调用者传递格式化参数 |
| 不必要的导入别名 | 别名增加认知负担。仅在冲突时使用别名——mrand "math/rand" |
| 不一致的概念名称 | 对同一概念使用 user/account/person 会迫使读者追踪同义词——选择一个名称 |
许多命名约定问题可以通过 linter 自动捕获:revive, predeclared, misspell, errname。有关配置和使用,请参阅 samber/cc-skills-golang@golang-linter 技能。
samber/cc-skills-golang@golang-code-style 技能,了解更广泛的格式和风格决策samber/cc-skills-golang@golang-structs-interfaces 技能,了解接口命名深度和接收器设计samber/cc-skills-golang@golang-linter 技能,了解自动执行(revive, predeclared, misspell, errname)每周安装次数
96
代码仓库
GitHub 星标数
184
首次出现
3 天前
安全审计
安装于
opencode78
codex77
gemini-cli77
kimi-cli76
github-copilot76
cursor76
Community default. A company skill that explicitly supersedes
samber/cc-skills-golang@golang-namingskill takes precedence.
Go favors short, readable names. Capitalization controls visibility — uppercase is exported, lowercase is unexported. All identifiers MUST use MixedCaps, NEVER underscores.
"Clear is better than clever." — Go Proverbs
"Design the architecture, name the components, document the details." — Go Proverbs
To ignore a rule, just add a comment to the code.
| Element | Convention | Example |
|---|---|---|
| Package | lowercase, single word | json, http, tabwriter |
| File | lowercase, underscores OK | user_handler.go |
| Exported name | UpperCamelCase | ReadAll, HTTPClient |
| Unexported | lowerCamelCase | parseToken, userCount |
| Interface | method name + -er | Reader, Closer, Stringer |
| Struct | MixedCaps noun | Request, FileHeader |
| Constant | MixedCaps (not ALL_CAPS) | MaxRetries, defaultTimeout |
| Receiver | 1-2 letter abbreviation | func (s *Server), func (b *Buffer) |
| Error variable | Err prefix | ErrNotFound, ErrTimeout |
| Error type | Error suffix | PathError, SyntaxError |
| Constructor | New (single type) or NewTypeName (multi-type) | ring.New, http.NewRequest |
| Boolean field | is, has, can prefix on fields and methods | isReady, IsConnected() |
| Test function | Test + function name | TestParseToken |
| Acronym | all caps or all lower | URL, HTTPServer, xmlParser |
| Variant: context | WithContext suffix | FetchWithContext, QueryContext |
| Variant: in-place | In suffix | SortIn(), ReverseIn() |
| Variant: error | Must prefix | MustParse(), MustLoadConfig() |
| Option func | With + field name | WithPort(), WithLogger() |
| Enum (iota) | type name prefix, zero-value = unknown | StatusUnknown at 0, StatusReady |
| Named return | descriptive, for docs only | (n int, err error) |
| Error string | lowercase (incl. acronyms), no punctuation | "image: unknown format", "invalid id" |
| Import alias | short, only on collision | mrand "math/rand", pb "app/proto" |
| Format func | f suffix | Errorf, Wrapf, Logf |
| Test table fields | got/expected prefixes | input string, expected int |
All Go identifiers MUST use MixedCaps (or mixedCaps). NEVER use underscores in identifiers — the only exceptions are test function subcases (TestFoo_InvalidInput), generated code, and OS/cgo interop. This is load-bearing, not cosmetic — Go's export mechanism relies on capitalization, and tooling assumes MixedCaps throughout.
// ✓ Good
MaxPacketSize
userCount
parseHTTPResponse
// ✗ Bad — these conventions conflict with Go's export mechanism and tooling expectations
MAX_PACKET_SIZE // C/Python style
max_packet_size // snake_case
kMaxBufferSize // Hungarian notation
Go call sites always include the package name, so repeating it in the identifier wastes the reader's time — http.HTTPClient forces parsing "HTTP" twice. A name MUST NOT repeat information already present in the package name, type name, or surrounding context.
// Good — clean at the call site
http.Client // not http.HTTPClient
json.Decoder // not json.JSONDecoder
user.New() // not user.NewUser()
config.Parse() // not config.ParseConfig()
// In package sqldb:
type Connection struct{} // not DBConnection — "db" is already in the package name
// Anti-stutter applies to ALL exported types, not just the primary struct:
// In package dbpool:
type Pool struct{} // not DBPool
type Status struct{} // not PoolStatus — callers write dbpool.Status
type Option func(*Pool) // not PoolOption
These conventions are correct but non-obvious — they are the most common source of naming mistakes:
Constructor naming: When a package exports a single primary type, the constructor is New(), not NewTypeName(). This avoids stuttering — callers write apiclient.New() not apiclient.NewClient(). Use NewTypeName() only when a package has multiple constructible types (like http.NewRequest, http.NewServeMux).
Boolean struct fields: Unexported boolean fields MUST use is/has/can prefix — isConnected, hasPermission, not bare connected or permission. The exported getter keeps the prefix: IsConnected() bool. This reads naturally as a question and distinguishes booleans from other types.
Error strings are fully lowercase — including acronyms. Write "invalid message id" not "invalid message ID", because error strings are often concatenated with other context (fmt.Errorf("parsing token: %w", err)) and mixed case looks wrong mid-sentence. Sentinel errors should include the package name as prefix: errors.New("apiclient: not found").
Enum zero values: Always place an explicit Unknown/Invalid sentinel at iota position 0. A var s Status silently becomes 0 — if that maps to a real state like StatusReady, code can behave as if a status was deliberately chosen when it wasn't.
Subtest names: Table-driven test case names in t.Run() should be fully lowercase descriptive phrases: "valid id", "empty input" — not "valid ID" or "Valid Input".
For complete rules, examples, and rationale, see:
Packages, Files& Import Aliasing — Package naming (single word, lowercase, no plurals), file naming conventions, import alias patterns (only use on collision to avoid cognitive load), and directory structure.
Variables, Booleans, Receivers& Acronyms — Scope-based naming (length matches scope: i for 3-line loops, longer names for package-level), single-letter receiver conventions (s for Server), acronym casing (URL not Url, HTTPServer not HttpServer), and boolean naming patterns (isReady, hasPrefix).
Functions, Methods& Options — Getter/setter patterns (Go omits Get so user.Name() reads naturally), constructor conventions (New or NewTypeName), named returns (for documentation only), format function suffixes (, ), and functional options (, ).
| Mistake | Fix |
|---|---|
ALL_CAPS constants | Go reserves casing for visibility, not emphasis — use MixedCaps (MaxRetries) |
GetName() getter | Go omits Get because user.Name() reads naturally at call sites. But Is/Has/Can prefixes are kept for boolean predicates: not |
Many naming convention issues are caught automatically by linters: revive, predeclared, misspell, errname. See samber/cc-skills-golang@golang-linter skill for configuration and usage.
samber/cc-skills-golang@golang-code-style skill for broader formatting and style decisionssamber/cc-skills-golang@golang-structs-interfaces skill for interface naming depth and receiver designsamber/cc-skills-golang@golang-linter skill for automated enforcement (revive, predeclared, misspell, errname)Weekly Installs
96
Repository
GitHub Stars
184
First Seen
3 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode78
codex77
gemini-cli77
kimi-cli76
github-copilot76
cursor76
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
123,700 周安装
ErrorfWrapfWithPortWithLoggerTypes, Constants& Errors — Interface naming (Reader, Closer suffix with -er), struct naming (nouns, MixedCaps), constants (MixedCaps, not ALL_CAPS), enums (type name prefix like StatusReady), sentinel errors (ErrNotFound variables), error types (PathError suffix), and error message conventions (lowercase, no punctuation).
Test Naming — Test function naming (TestFunctionName), table-driven test field conventions (input, expected), test helper naming, and subcase naming patterns.
IsHealthy() boolHealthy() boolUrl, Http, Json acronyms | Mixed-case acronyms create ambiguity (HttpsUrl — is it Https+Url?). Use all caps or all lower |
this or self receiver | Go methods are called frequently — use 1-2 letter abbreviation (s for Server) to reduce visual noise |
util, helper packages | These names say nothing about content — use specific names that describe the abstraction |
http.HTTPClient stuttering | Package name is always present at call site — http.Client avoids reading "HTTP" twice |
user.NewUser() constructor | Single primary type uses New() — user.New() avoids repeating the type name |
connected bool field | Bare adjective is ambiguous — use isConnected so the field reads as a true/false question |
"invalid message ID" error | Error strings must be fully lowercase including acronyms — "invalid message id" |
StatusReady at iota 0 | Zero value should be a sentinel — StatusUnknown at 0 catches uninitialized values |
"not found" error string | Sentinel errors should include the package name — "mypackage: not found" identifies the origin |
userSlice type-in-name | Types encode implementation detail — users describes what it holds, not how |
| Inconsistent receiver names | Switching names across methods of the same type confuses readers — use one name consistently |
snake_case identifiers | Underscores conflict with Go's MixedCaps convention and tooling expectations — use mixedCaps |
| Long names for short scopes | Name length should match scope — i is fine for a 3-line loop, userIndex is noise |
| Naming constants by value | Values change, roles don't — DefaultPort survives a port change, Port8080 doesn't |
FetchCtx() context variant | WithContext is the standard Go suffix — FetchWithContext() is instantly recognizable |
sort() in-place but no In | Readers assume functions return new values. SortIn() signals mutation |
parse() panicking on error | MustParse() warns callers that failure panics — surprises belong in the name |
Mixing With*, Set*, Use* | Consistency across the codebase — With* is the Go convention for functional options |
| Plural package names | Go convention is singular (net/url not net/urls) — keeps import paths consistent |
Wrapf without f suffix | The f suffix signals format-string semantics — Wrapf, Errorf tell callers to pass format args |
| Unnecessary import aliases | Aliases add cognitive load. Only alias on collision — mrand "math/rand" |
| Inconsistent concept names | Using user/account/person for the same concept forces readers to track synonyms — pick one name |