当前位置: 首页 > news >正文

Go Style 代码风格规范

Golang 代码 编程规范

Go 代码应该以最简单的方式编写,以实现其目标,无论是在行为还是性能方面。在 Google Go 代码库中,简单代码:

  • 从上到下都易于阅读;
  • 不假设你已经知道它在做什么;
  • 不假设你可以记住所有前面的代码;
  • 没有不必要的抽象层次;
  • 没有能引起关注的世俗名称;
  • 让开发者清楚地了解价值观和决策的传播;
  • 有注释解释代码为什么这样做,而不是做什么,以避免将来出现偏差;
  • 有独立的文档;
  • 有 有用的错误和有用的失败测试;
  • 可能经常与“聪明”的代码互相排斥。

参考指南:

  • https://google.github.io/styleguide/go/best-practices

  • https://go.dev/wiki/CodeReviewComments

  • https://google.github.io/styleguide/go/

  • https://go.dev/doc/effective_go

1. gofmt 统一代码格式

执行 go fmt ./... 来统一代码格式。

2. 注释说明增强

在会引发歧义或者和上文判断不同时使用注释以提醒开发者。

if err := doSomething(); err != nil {// ...
}if err := doSomething(); err == nil { // if NO error// ...
}
3. 注释应该说明的是”为什么“,而不是”做什么“
// ❌ Bad
// Increment i by 1
i = i + 1// ✅ Good
// Retry count is increased after each failed attempt.
i++
4. 当有 context.Context 参数时,其永远是方法的第一个参数并且不被放在结构体中
// ❌ Bad
type ServerContext struct {ctx context.Context// other 
}func (s *ServerContext) doSomething(param any, ctx context.Context) {// ...
}// ✅ Good
type ServerContext struct {// other 
}func (s *ServerContext) doSomething(ctx context.Context, param any) {// ...
}
5. 正确声明变量
// ❌ Bad
// nil 
s := []int8{}// ✅ Good
// 非零但长度为零
var s []inti := 42

[]T{} 会默认分配内存,var s []T 更清晰与高效。

在使用非零值初始化时,使用 := 赋值。

6. 代码中不要出现 panic
// ❌ Bad
func ParseConfig(file *os.File, cfg any) {decoder := yaml.NewDecoder(file)if err := decoder.Decode(cfg); err != nil {panic("failed to decode config: " + err.Error())}
}// ✅ Good
func Parse(file *os.File, cfg any) error {decoder := yaml.NewDecoder(file)if err := decoder.Decode(cfg); err != nil {return err}return nil
}

依赖库应该优先返回 err,而不是终止程序。

7. 保持错误信息干净,使用结构化日志
// ❌ Bad
return fmt.Errorf("some error.")// ✅ Good
return fmt.Errorf("some error.")

error msg 小写开头且不以任何标点结尾。

8. 避免多余的 else 逻辑
// ❌ Bad
if err != nil {if something {return err}
} else {doSomething()
}// ✅ Good
if err != nil {return err
}
doSomething()

尽早返回 error 且避免多余的 else 语句。

9. 使用包别名导入

除非为了避免名称冲突,否则应避免重命名导入;好的包名称不应该需要重命名。如果发生冲突,优先重命名本地或项目特定的导入。

import pkg 按组组织,每组之间以空行分隔。标准库包始终位于第一组,其次是第三方包,最后是项目内部包。

10. 缩写保持大写和官方库一致
// ❌ Bad
type HttpServer struct{}// ✅ Good
type HTTPServer struct{}

标准库写法:HTTP、ID、JSON。保持一致性.

11. 避免裸返回
// ❌ Bad
func sum(a, b int) (result int) {result = a + breturn
}// ✅ Good
func sum(a, b int) int {return a + b
}

除非函数非常短,一眼看到底时使用裸返回。

12. 包名、接受者名保持简单与简洁切避免函数名重复与啰嗦
// ❌ Bad
package my_utilsfunc (this *Server) Start() {}package yamlconfig
func ParseYAMLConfig(input string) (*Config, error)func OverrideFirstWithSecond(dest, source *Config) error// 不应书写函数的返回参数名,这会导致 goDoc 混乱
func doSomething(a, b int) (sum int, err error) {// logic
}// ✅ Good
package utilsfunc (s *Server) Start() package yamlconfig
func Parse(input string) (*Config, error)func Override(dest, source *Config) errorfunc doSomething(a, b int) (int,error) {// logic
}
  • 包名小写、简洁、无下划线;
  • 接受者变量 s, r, c 这种短变量常见且清晰;
  • 包名提供上下文。

当需要消除类似名称的函数歧义时,可以包含额外的信息。

// ✅ Good
func (c *Config) WriteTextTo(w io.Writer) (int64, error)
func (c *Config) WriteBinaryTo(w io.Writer) (int64, error)
13. 函数名中不应出现返回类型且命名体现语义
// ❌ Bad
func TransformToJSON(input *Config) *jsonconfig.Configfunc (c *Config) GetJobName(key string) (value string, ok bool)// ✅ Good
func Transform(input *Config) *jsonconfig.Config// 返回值函数中不要动词
func (c *Config) JobName(key string) (value string, ok bool)// 动作用动词,取值用名词
func (c *Config) ApplyChanges() error
func ProcessData(data []byte) error

动作用动词,取值用名词且返回值函数中不要动词。

14. 测试写法符合 Go got %v, want %v风格
// ❌ Bad
if got != want {t.Errorf("expected %v but got %v", want, got)
}// ✅ Good
if got != want {t.Errorf("got %v, want %v", got, want)
}
15. 常量与结构化错误声明
type Animal stringvar (// ErrDuplicate occurs if this animal has already been seen.ErrDuplicate = errors.New("duplicate")// ErrMarsupial occurs because we're allergic to marsupials outside Australia.// Sorry.ErrMarsupial = errors.New("marsupials are not supported")
)func process(animal Animal) error {switch {case seen[animal]:return ErrDuplicatecase marsupial(animal):return ErrMarsupial}seen[animal] = true// ...return nil
}

在使用到常量定义或者错误时,将其机构化定义在文件顶部或统一管理。

16. 当函数参数列表过多时,使用可变参数处理输入
type SshProtocol struct {Host                 stringPort                 stringTimeout              stringUsername             stringPassword             stringPrivateKey           stringPrivateKeyPassphrase stringReuseConnection      stringScript               stringParseType            stringProxyHost            stringProxyPort            stringProxyUsername        stringProxyPassword        stringUseProxy             stringProxyPrivateKey      string
}type SshProtocolConfigOptFunc func(option *SshProtocol)func NewSshProtocol(host, port string, opts ...SshProtocolConfigOptFunc) *SshProtocol {option := &SshProtocol{Host: host,Port: port,}for _, opt := range opts {opt(option)}return &SshProtocol{Host:                 host,Port:                 port,Timeout:              option.Timeout,Username:             option.Username,Password:             option.Password,PrivateKey:           option.PrivateKey,PrivateKeyPassphrase: option.PrivateKeyPassphrase,ReuseConnection:      option.ReuseConnection,Script:               option.Script,ParseType:            option.ParseType,ProxyHost:            option.ProxyHost,ProxyPort:            option.ProxyPort,ProxyUsername:        option.ProxyUsername,ProxyPassword:        option.ProxyPassword,UseProxy:             option.UseProxy,ProxyPrivateKey:      option.ProxyPrivateKey,}
}func (sp *SshProtocol) IsInvalid() error {return nil
}
17. 字符串拼接
// 连接少量字符时使用 + 
key := "projectid: " + p// 构建带有格式化的复杂字符串时,优先使用 fmt.Sprintf
str := fmt.Sprintf("%s [%s:%d]-> %s", src, qos, mtu, dst)// 字符串格式更加复杂时,优先使用 text/template 或 safehtml/template

文章转载自:

http://HnXcKJbA.gwjsm.cn
http://3tLMfDKN.gwjsm.cn
http://mhpCr8xq.gwjsm.cn
http://wWkGdpgE.gwjsm.cn
http://K6xte8X4.gwjsm.cn
http://xZBPVBh6.gwjsm.cn
http://GeSAtSjx.gwjsm.cn
http://2GfPmH1J.gwjsm.cn
http://eO50ZRKf.gwjsm.cn
http://1wo07vh8.gwjsm.cn
http://sqdCj2Wl.gwjsm.cn
http://LKBnMGft.gwjsm.cn
http://1I8KGm89.gwjsm.cn
http://0xrZpt6l.gwjsm.cn
http://FQhtNHsi.gwjsm.cn
http://0wa2jfeH.gwjsm.cn
http://FP1FlXNs.gwjsm.cn
http://Wyv1pDEj.gwjsm.cn
http://q5E6sS5c.gwjsm.cn
http://6XAbkdnB.gwjsm.cn
http://1V7jre3D.gwjsm.cn
http://wG4vVzPN.gwjsm.cn
http://IDj73Dsc.gwjsm.cn
http://AXZucyYB.gwjsm.cn
http://rGzMETCt.gwjsm.cn
http://ROalU1tT.gwjsm.cn
http://2ZkEzicq.gwjsm.cn
http://rpXdBdzz.gwjsm.cn
http://tQf0X8ws.gwjsm.cn
http://xubEqP9Z.gwjsm.cn
http://www.dtcms.com/a/373414.html

相关文章:

  • Java 16 中引入的 record的基本用法
  • uni-app iOS 性能监控全流程 多工具协作的实战优化指南
  • shell 中 expect 详解
  • 告别低效:构建健壮R爬虫的工程思维
  • Ubuntu中显示英伟达显卡的工具软件或者指令
  • 银行卡号识别案例
  • 【golang学习笔记 gin 】1.2 redis 的使用
  • AI提示词(Prompt)基础核心知识点
  • VTK开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo
  • Excel 表格 - Excel 减少干扰、专注于内容的查看方式
  • Vue3 + Ant Design Vue 全局配置中文指南
  • CSS in JS 的演进:Styled Components, Emotion 等的深度对比与技术选型指引
  • 哈士奇vs网易高级数仓:数据仓库的灵魂是模型、数据质量还是计算速度?| 易错题
  • Windows 命令行:cd 命令2,切换到多级子目录
  • C++ 8
  • GD32入门到实战45--LVGL开发(Code::Blocks)之创建控件
  • 算法题(202):乌龟棋
  • 国产化服务注册与发现工具nacos安装
  • WordPress 性能优化:从插件到 CDN 的全方位缓存设置指南
  • 所有微服务部署都使用一个git地址,并且通过docker部署各个服务的情况下,如何编写mvn指令来处理各个服务。
  • 【AI】乡村振兴计划书:AI智能农业与设备研发销售一体化项目
  • 408 Request Timeout:请求超时,服务器等待客户端发送请求的时间过长。
  • 从车辆中心到用户中心:E/E架构的变革与挑战
  • 基于Mysql+SpringBoot+vue框架-校园商铺管理系统源码
  • SQL MERGE语句实战:高效增量数据处理
  • AI 云再进化,百度智能云新技术与产品全景解读
  • react 面试题 react 有什么特点?
  • PyTorch 模型保存与加载 (速查版)
  • MCU-在SOTA过程中基于TC397的AB-SWAP切换底层原理
  • Python+DRVT 从外部调用 Revit:批量创建带孔洞楼板