持续更新中…
原文最新链接
https://github.com/golang/go/wiki/CodeReviewComments/5a40ba36d388ff1b8b2dd4c1c3fe820b8313152f
Github译文链接
https://github.com/wddpct/articles/issues/8
对于刚开始学习和使用 Go 的新手来说,有这么几个资源值得关注。
- A Tour of Go
- How to Write Go Code
- Frequently Asked Questions (FAQ)
- The Go Blog Index
- The Go Wiki
- Effective Go
- Go Code Review Comments
- ……
Effective Go 和 Go Code Review Comments 中介绍了很多有助于编写优雅,高效的 Go 代码的指导性原则,前者可以认为是官方权威指南,而后者则可以算是对前者的补充,原文托管在 Github 上,每个月都会做部分 fix,而网上的中文版大多都是历史版本,无法及时更新,所以想由自己在业余时做些额外的工作,水平一般,能力有限,少部分难以翻译的词句将附上原文或给出意译内容。以下是翻译正文。
Go Code Review Comments
当前页面收集了在 Go 代码审核期间的常见意见,以便一个详细说明能被快速参考。这是一个常见错误的清单,而非综合性的风格指南。
你也可以将它作为是 Effective Go 的补充。
请在编辑这个页面前先讨论这个变更,就算是一个很小的变更。毕竟许多人都有自己的想法,而这里并不是战场。
- Gofmt
- Comment Sentences
- Contexts
- Copying
- Crypto Rand
- Declaring Empty Slices
- Doc Comments
- Don't Panic
- Error Strings
- Examples
- Goroutine Lifetimes
- Handle Errors
- Imports
- Import Dot
- In-Band Errors
- Indent Error Flow
- Initialisms
- Interfaces
- Line Length
- Mixed Caps
- Named Result Parameters
- Naked Returns
- Package Comments
- Package Names
- Pass Values
- Receiver Names
- Receiver Type
- Synchronous Functions
- Useful Test Failures
- Variable Names
Gofmt
在 Go 代码上运行 gofmt 以自动修复大多数的机械性风格问题。几乎所有不正规的 Go 代码都在使用gofmt
。本文档的剩余部分涉及非机械性风格问题。
另一种方法是使用 goimports,这是gofmt
的超集,gofmt
可根据需要额外添加(和删除)导入行。
Comment Sentences
参见 https://golang.org/doc/effective_go.html#commentary。注释文档声明应该是完整的句子,即使这看起来有些多余。这种方式使注释在提取到 godoc 文档时格式良好。注释应以所描述事物的名称开头,并以句点结束:
// Request represents a request to run a command.
type Request struct { ...
// Encode writes the JSON encoding of req to w.
func Encode(w io.Writer, req *Request) { ...
请注意除了句点之外还有其他符号可以作为句子的有效结尾(但至少也应该是!,?)。除此之外,还有许多工具使用注释来标记类型和方法(如 easyjson:json 和 golint 的 MATCH)。这使得这条规则难以形式化。
Contexts
A function that is never request-specific may use context.Background(), but err on the side of passing a Context even if you think you don't need to. The default case is to pass a Context; only use context.Background() directly if you have a good reason why the alternative is a mistake.
context.Context 类型的值包含跨 API 和进程边界的安全凭证,跟踪信息,截止时间和取消信号。比如传入 RPC 请求和 HTTP 请求一直到传出相关请求,Go 程序在整个过程的函数调用链中显式地传递 Context。
大多数使用 Context 的函数都应该接受 Context 作为函数的第一个参数:
func F(ctx context.Context, /* other arguments */) {}
从不特定于请求(request-specific)的函数可以使用 context.Background() 获取 Context,并将 err 与 Context 同时传递,即使你认为不需要。默认情况下只传递 Context ;只在你有充分的理由认为这是错误的,才能直接使用context.Background()。
原文: A function that is never request-specific may use context.Background(), but err on the side of passing a Context even if you think you don't need to. The default case is to pass a Context; only use context.Background() directly if you have a good reason why the alternative is a mistake.
不要将 Context 成员添加到某个 struct 类型中;而是将 ctx 参数添加到该类型的方法上。一个例外情况是当前方法签名必须与标准库或第三方库中的接口方法匹配。
不要在函数签名中创建自定义 Context 类型或使用除了 Context 以外的接口。
如果要传递应用程序数据,请将其放在参数,方法接收器,全局变量中,或者如果它确实应该属于 Context,则放在 Context 的 Value 属性中。
所有的 Context 都是不可变的,因此可以将相同的 ctx 传递给多个共享相同截止日期,取消信号,安全凭据,跟踪等的调用。
Copying
为避免意外的别名,从另一个包复制 struct 时要小心。例如,bytes.Buffer 类型包含一个 []byte 的 slice,并且作为短字符串的优化,slice 可以引用一个短字节数组。如果复制一个 Buffer,副本中的 slice 可能会对原始数组进行别名操作,从而导致后续方法调用产生令人惊讶的效果。
通常,如果 T 类型的方法与其指针类型 *T 相关联,请不要复制 T 类型的值。
Crypto Rand
不要使用包math/rand
来生成密钥,即使是一次性密钥。在没有种子(seed)的情况下,生成器是完全可以被预测的。使用time.Nanoseconds()
作为种子值,熵只有几位。请使用crypto/rand
的 Reader 作为替代,如果你倾