uber-go/guide 的中文翻译
English
Uber Go 语言编码规范
Uber 是一家美国硅谷的科技公司,也是 Go 语言的早期 adopter。其开源了很多 golang 项目,诸如被 Gopher 圈熟知的 zap、jaeger 等。2018 年年末 Uber 将内部的 Go 风格规范 开源到 GitHub,经过一年的积累和更新,该规范已经初具规模,并受到广大 Gopher 的关注。本文是该规范的中文版本。本版本会根据原版实时更新。
版本
- 当前更新版本:2024-08-10 版本地址:commit:#217
- 如果您发现任何更新、问题或改进,请随时 fork 和 PR
- Please feel free to fork and PR if you find any updates, issues or improvement.
目录
- uber-go/guide 的中文翻译
- English
- Uber Go 语言编码规范
- 版本
- 目录
- 介绍
- 指导原则
- 指向 interface 的指针
- Interface 合理性验证
- 接收器 (receiver) 与接口
- 零值 Mutex 是有效的
- 在边界处拷贝 Slices 和 Maps
- 使用 defer 释放资源
- Channel 的 size 要么是 1,要么是无缓冲的
- 枚举从 1 开始
- 使用 time 处理时间
- Errors
- 处理断言失败
- 不要使用 panic
- 使用 go.uber.org/atomic
- 避免可变全局变量
- 避免在公共结构中嵌入类型
- 避免使用内置名称
- 避免使用
init()
- 追加时优先指定切片容量
- 主函数退出方式 (Exit)
- 在序列化结构中使用字段标记
- 不要一劳永逸地使用 goroutine
- 性能
- 规范
- 编程模式
- Linting
- Stargazers over time
介绍
样式 (style) 是支配我们代码的惯例。术语样式
有点用词不当,因为这些约定涵盖的范围不限于由 gofmt 替我们处理的源文件格式。
本指南的目的是通过详细描述在 Uber 编写 Go 代码的注意事项来管理这种复杂性。这些规则的存在是为了使代码库易于管理,同时仍然允许工程师更有效地使用 Go 语言功能。
该指南最初由 Prashant Varanasi 和 Simon Newton 编写,目的是使一些同事能快速使用 Go。多年来,该指南已根据其他人的反馈进行了修改。
本文档记录了我们在 Uber 遵循的 Go 代码中的惯用约定。其中许多是 Go 的通用准则,而其他扩展准则依赖于下面外部的指南:
我们的目标是使代码示例能够准确地用于Go的两个发布版本 releases.
所有代码都应该通过golint
和go vet
的检查并无错误。我们建议您将编辑器设置为:
- 保存时运行
goimports
- 运行
golint
和go vet
检查错误
您可以在以下 Go 编辑器工具支持页面中找到更为详细的信息: https://go.dev/wiki/IDEsAndTextEditorPlugins
指导原则
指向 interface 的指针
您几乎不需要指向接口类型的指针。您应该将接口作为值进行传递,在这样的传递过程中,实质上传递的底层数据仍然可以是指针。
接口实质上在底层用两个字段表示:
- 一个指向某些特定类型信息的指针。您可以将其视为"type"。
- 数据指针。如果存储的数据是指针,则直接存储。如果存储的数据是一个值,则存储指向该值的指针。
如果希望接口方法修改基础数据,则必须使用指针传递 (将对象指针赋值给接口变量)。
type F interface {
f()
}
type S1 struct{}
func (s S1) f() {}
type S2 struct{}
func (s *S2) f() {}
// f1.f() 无法修改底层数据
// f2.f() 可以修改底层数据,给接口变量 f2 赋值时使用的是对象指针
var f1 F = S1{}
var f2 F = &S2{}
永远不要使用指向interface的指针,这个是没有意义的.在go语言中,接口本身就是引用类型,换句话说,接口类型本身就是一个指针。对于我的需求,其实test的参数只要是myinterface就可以了,只需要在传值的时候,传mystruct类型(也只能传mystruct类型)
type myinterface interface{
print()
}
func test(value *myinterface){
//someting to do ...
}
type mystruct struct {
i int
}
//实现接口
func (this *mystruct) print(){
fmt.Println(this.i)
this.i=1
}
func main(){
m := &mystruct{0}
test(m)//错误
test(*m)//错误
}
Interface 合理性验证
在编译时验证接口的符合性。这包括:
- 将实现特定接口的导出类型作为接口 API 的一部分进行检查
- 实现同一接口的 (导出和非导出) 类型属于实现类型的集合
- 任何违反接口合理性检查的场景,都会终止编译,并通知给用户
补充:上面 3 条是编译器对接口的检查机制, 大体意思是错误使用接口会在编译期报错。 所以可以利用这个机制让部分问题在编译期暴露。
Bad | Good |
---|---|
|
|