Golang 代码规范 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 ⽂档时格式良好。注释应以所描述事物的名称开头,并以句点结束: 1. // Request represents a request to run a command. 2. type Request struct { ... 3. 4. // Encode writes the JSON encoding of req to w. 5. func Encode(w io.Writer, req *Request) { ... 请注意除了句点之外还有其他符号可以作为句⼦的有效结尾(但⾄少也应该是!,?)。除此之外,还有许多⼯具使⽤注释来标记类型和⽅法(如 easyjson:json 和 golint 的 MATCH)。这使得这条规则难以形式化。 Contexts context.Context 类型的值包含跨 API 和进程边界的安全凭证,跟踪信息,截⽌时间和取消信号。⽐如传⼊ RPC 请求和 HTTP 请求⼀直到传出相 关请求,Go 程序在整个过程的函数调⽤链中显式地传递 Context。 ⼤多数使⽤ Context 的函数都应该接受 Context 作为函数的第⼀个参数: 1. 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 作为替代,如果你倾向于使⽤⽂本,请输出成⼗六进制或 base64 编码: 1. import ( 2. "crypto/rand" 3. // "encoding/base64" 4. // "encoding/hex" 5. "fmt" 6. ) 7. 8. func Key() string { 9. buf := make([]byte, 16) 10. _, err := rand.Read(buf) 11. if err != nil { 12. panic(err) // out of randomness, should never happen 13. } 14. return fmt.Sprintf("%x", buf) 15. // or hex.EncodeToString(buf) 16. // or base64.StdEncoding.EncodeToString(buf) 17. } Declaring Empty Slices 当声明⼀个空 slice 时,倾向于⽤ 1. var t []string 代替 1. t := []string{} 前者声明了⼀个 nil slice 值,⽽后者声明了⼀个⾮ nil 但是零⻓度的 slice。两者在功能上等同,len 和 cap 均为零,⽽ nil slice 是⾸选的⻛格。 请注意,在部分场景下,⾸选⾮零但零⻓度的切⽚,例如编码 JSON 对象时(前者编码为 null,⽽后者则可以正确编码为 JSON array[])。 在设计 interface 时,避免区分 nil slice 和 ⾮ nil,零⻓度的 slice,因为这会导致细微的编程错误。 有关 Go 中对于 nil 的更多讨论,请参阅 Francesc Campoy 的演讲 Understanding Nil。 Doc Comments 所有的顶级导出的名称都应该有 doc 注释,重要的未导出类型或函数声明也应如此。有关注释约束的更多信息,请参阅 https://golang.org/doc/effective_go.html#commentary。 Don't Panic 请参阅 https://golang.org/doc/effective_go.html#errors。不要将 panic ⽤于正常的错误处理。使⽤ error 和多返回值。 Error Strings Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context. That is, use fmt.Errorf("something bad") not fmt.Errorf("Something bad"), so that log.Printf("Reading %s: %v", filename, err) formats without a spurious capital letter mid-message. This does not apply to logging, which is implicitly line-oriented and not combined inside other messages. 错误信息字符串不应⼤写(除⾮以专有名词或⾸字⺟缩略词开头)或以标点符号结尾,因为它们通常是在其他上下⽂后打印的。即使 ⽤fmt.Errorf("something bad")⽽不要使⽤fmt.Errorf("Something bad"),因此log.Printf("Reading %s: %v", filename, err)的格式中将不会出现额外的⼤写字⺟。否则这将不适⽤于⽇志记录,因为它是隐式的⾯向⾏,⽽不是在其他消息中组合。 Examples When adding a new package, include examples of intended usage: a runnable Example, or a simple test demonstrating a complete call sequence. Read more about testable Example() functions. 添加新包时,请包含预期⽤法的⽰例:可运⾏的⽰例,或是演⽰完整调⽤链的简单测试。 阅读有关 testable Example() functions 的更多信息。 Goroutine Lifetimes 当你⽣成 goroutines 时,
Golang 代码规范
温馨提示:如果当前文档出现乱码或未能正常浏览,请先下载原文档进行浏览。