☰
Uber Go 编码规范精讲:函数命名(Function Names)的 MixedCaps 约定与测试函数下划线分组
2026/9/26 18:58:54 网站建设 项目流程
  • 文档

【免费下载链接】uber_go_guide_cn

Uber Go 语言编码规范中文版. The Uber Go Style Guide .

项目地址:https://gitcode.com/gh_mirrors/ub/uber_go_guide_cn
点击查看免费下载

本文是《Uber Go 语言编码规范》(uber_go_guide_cn 仓库,对应规范条目见 src/function-name.md)中"函数命名"一节的深度解读。核心主题:Go 函数名一律遵循 MixedCaps(混合大小写)约定、测试函数是唯一允许使用下划线的例外;配套讲解 Printf 风格函数、错误值、包名等相关命名规则,并给出与表驱动测试、go vet 工具链结合的实战建议。读完本文,你将掌握一套可落地、可被go vet与代码评审自动校验的 Go 函数命名体系。

一、核心规则:函数名使用 MixedCaps

规范原文的第一条原则非常简短但分量极重:

We follow the Go community's convention of using MixedCaps for function names.

即:函数命名遵循 Go 社区通行约定——MixedCaps(混合大小写)。这条约定源自 Go 官方的 Effective Go 文档,是整个 Go 标识符命名体系(变量、常量、类型、函数、方法)的共同基石。

1.1 什么是 MixedCaps

MixedCaps 是指:

  • 不使用下划线(_)连接单词;
  • 多单词名称采用驼峰式拼接:首字母大写(导出)或小写(非导出),后续每个单词首字母大写。
场景推荐命名(MixedCaps)不推荐(下划线/全小写)
导出函数ParseConfig,NewServerparse_config,newserver
非导出函数parseConfig,newServerparse_config,parseconfig
接收器方法(s *Server) StartTLS()(s *Server) start_tls()

MixedCaps这个名字本身就混合了大写和小写,生动地说明了该约定的字面含义:MixedCaps而不是mixed_caps。

1.2 为什么 Go 社区约定用 MixedCaps

从语言设计角度看,Go 的导出可见性规则与命名约定深度绑定:

  • 首字母大写的标识符(如ParseConfig)会被导出,对包外可见;
  • 首字母小写的标识符(如parseConfig)仅在包内可见。

如果允许下划线,可见性判断会被"下划线前缀/后缀"干扰,可读性与工具链分析都会变复杂。统一使用 MixedCaps,可以让"大小写"成为判断导出状态的唯一信号,这也是golint、go vet及各类 IDE 静态检查默认遵循的规则。

二、唯一例外:测试函数允许下划线

规范的完整原文为:

An exception is made for test functions, which may contain underscores for the purpose of grouping related test cases, e.g.,TestMyFunction_WhatIsBeingTested.

测试函数是唯一的例外:允许(且鼓励)在函数名中使用下划线,目的是对相关的测试用例进行分组。规范给出的标准范式是:

func TestMyFunction_WhatIsBeingTested(t *testing.T)

即采用Test<被测函数名>_<被测试的具体行为>的格式,下划线把"被测对象"与"测试场景"清晰分隔。

2.1 分组命名的实战价值

为什么需要下划线分组?当一个函数有多个行为分支时,用多个独立的测试函数可以精确表达"测的是什么":

func TestParseConfig_ReturnsErrorOnMissingFile(t *testing.T) { ... } func TestParseConfig_ReturnsErrorOnInvalidSyntax(t *testing.T) { ... } func TestParseConfig_SetsDefaultsWhenFieldsOmit(t *testing.T) { ... }

这种命名带来的直接收益:

  • 失败信息可定位:测试失败时,测试名本身就是一份"行为规格说明书",无需翻代码即可判断是哪个分支出了问题;
  • 测试报告可读:go test -v输出的测试名即文档;
  • 与子测试(subtests)配合:配合表驱动测试中的t.Run(name, ...),可以形成"函数名(场景分组)→ 子测试名(具体输入/输出)"的层级结构。

2.2 与表驱动测试(Test Tables)组合使用

Uber 规范中另一条目 表驱动测试 与上述命名约定天然互补。表驱动测试要求用切片tests与循环变量tt组织用例,并用give/want前缀标明输入输出:

func TestSplitHostPort(t *testing.T) { tests := []struct { give string wantHost string wantPort string }{ {give: "192.0.2.0:8000", wantHost: "192.0.2.0", wantPort: "8000"}, {give: "192.0.2.0:http", wantHost: "192.0.2.0", wantPort: "http"}, {give: ":8000", wantHost: "", wantPort: "8000"}, {give: "1:8", wantHost: "1", wantPort: "8"}, } for _, tt := range tests { t.Run(tt.give, func(t *testing.T) { host, port, err := net.SplitHostPort(tt.give) require.NoError(t, err) assert.Equal(t, tt.wantHost, host) assert.Equal(t, tt.wantPort, port) }) } }

此时外层函数名TestSplitHostPort保持 MixedCaps(不含下划线),而每个t.Run(tt.give, ...)的子测试名直接使用输入值。当被测函数有多种"行为模式"(成功/失败、默认值/显式值)时,再使用TestXxx_WhatIsBeingTested的下划线分组格式拆成多个测试函数,避免在单个表格里塞入大量shouldErr、shouldCallX之类的条件分支——这一点在 表驱动测试 的"避免表格测试中不必要的复杂性"一节有专门论述。

2.3 并行测试(t.Parallel)时的命名注意事项

在并行子测试中,下划线分组命名尤其重要:当测试失败时,你需要在并行输出中快速识别是哪一组用例失败。参见 表驱动测试 中关于t.Parallel()的示例:

for _, tt := range tests { tt := tt // for t.Parallel t.Run(tt.give, func(t *testing.T) { t.Parallel() // ... }) }

务必在循环体内显式声明迭代变量tt := tt,否则并行运行的大多数测试会拿到错误的tt值——这会让命名良好的测试也"张冠李戴",排查成本陡增。

三、与函数命名配套的相邻规则(仓库佐证)

《Uber Go 编码规范》将"函数名"安排在 Style / 规范 章节,与一系列命名规则互为表里。下面是本仓库中与函数命名直接相关的几条,建议一并阅读:

3.1 命名 Printf 风格函数:让 go vet 能识别

命名 Printf 样式的函数 规定:声明Printf风格函数时,应确保go vet能识别并检查其格式化字符串。

  • 优先使用预定义名称:Printf、Sprintf、Errorf等,go vet默认检查这些名称;
  • 自定义名称必须以f结尾:例如Wrapf而不是Wrap;
  • 可用go vet -printfuncs=wrapf,statusf让go vet额外检查指定的自定义函数。

这条规则与 MixedCaps 共同构成函数命名的一部分:f后缀是"格式化函数"的命名约定,与驼峰拼写一致(Wrapf而非wrap_f)。

3.2 错误命名:Err 前缀与 Error 后缀

错误命名 针对全局错误变量给出了独立于下划线规则的约定:

var ( ErrBrokenLink = errors.New("link is broken") // 导出错误:Err 前缀 ErrCouldNotOpen = errors.New("could not open") errNotFound = errors.New("not found") // 非导出错误:err 前缀 ) type NotFoundError struct { ... } // 自定义错误类型:Error 后缀

注意该文档明确说明:"This guidance supersedes the Prefix Unexported Globals with _",即错误变量的命名优先于_ 前缀全局变量 规则。函数与错误值的命名虽然对象不同,但共享同一原则——用前缀/后缀传递语义信息(Err=可匹配的错误值、Error=错误类型、f=格式化函数)。

3.3 包命名与函数名的一致性

包名 要求包名"全部小写、无大写与下划线、简短、不用复数"。包名是函数名的"命名空间前缀":调用url.Parse时,包名url与函数名Parse(MixedCaps)拼接出完整可读的调用表达式。包名不用下划线,正是为了保证"包名 + MixedCaps 函数名"整体可读。

3.4 函数分组与顺序

函数分组与顺序 规定:文件内函数按接收器分组、按调用顺序大致排序;newXYZ()/NewXYZ()放在类型定义之后、其余方法之前;工具函数放在文件末尾。命名与排版双管齐下,才能让一个文件"扫一眼名字就知道结构"。

四、工具链落地方案

规范 Linting 章节要求所有代码通过golint与go vet检查,并建议编辑器在保存时运行goimports。针对函数命名,可以这样落地:

  1. 保存时运行goimports:自动处理导入与基础排版,保证命名相关的行宽、缩进一致;
  2. 运行go vet:自动识别 Printf 风格函数并检查格式串(配合-printfuncs覆盖自定义函数);
  3. 运行golint:对导出函数名的大小写、注释规范给出提示;
  4. 代码评审清单(可直接用于 Review):
    • 函数名是否为 MixedCaps,无下划线?
    • 非测试函数是否出现_(如my_func)?若有,改为myFunc;
    • 测试函数是否遵循TestXxx_WhatIsBeingTested分组范式?
    • Printf 风格自定义函数是否以f结尾?

五、总结

函数命名在 Go 中的规则可以用一句话概括:"MixedCaps 是默认,下划线只属于测试"。Uber 规范在 src/function-name.md 中给出的全部要点为:

  1. 函数名遵循 Go 社区 MixedCaps 约定(无下划线驼峰式);
  2. 唯一例外是测试函数,允许用下划线分组相关测试用例,范式为TestMyFunction_WhatIsBeingTested;
  3. 配合 命名 Printf 样式的函数(f后缀)、错误命名(Err/err前缀、Error后缀)、包名(全小写无下划线)等相邻规则,形成完整的命名体系;
  4. 通过go vet、golint与代码评审清单即可低成本落地。

命名是代码的"第一份文档"。当测试函数名能直接读出"被测对象 + 行为场景",当go vet能自动校验格式化函数——整个代码库的可维护性就会产生质的提升。

  • 文档

【免费下载链接】uber_go_guide_cn

Uber Go 语言编码规范中文版. The Uber Go Style Guide .

项目地址:https://gitcode.com/gh_mirrors/ub/uber_go_guide_cn
点击查看免费下载

相关推荐

上一篇:Prime Agent与GitHub Copilot对比:哪个AI编码助手更适合你?
下一篇:Atlas数据迁移工具终极对比:为什么选择Atlas而非Flyway/Liquibase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询