Gofmt
保存代码时一定要使用 gofmt
来格式化,所以最好在自己常用的 IDE 上面配置好对应的工具链,以下三个工具链是我常用的:
- gofmt
- goimport
- golangci-lint(可选)
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) { ...
Contexts
context.Context
类型的值为 API
和进程沟通携带安全凭据、跟踪信息、截止日期和取消信号。Go程序沿着从传入 rpc 和 HTTP 请求到传出请求的整个函数调用链显式地传递上下文。
context.Context
参数通常在方法的第一个参数中使用:
func F(ctx context.Context, /* other arguments */) {}
不是特定于请求的函数可以使用 Context.Background()
,但即使您认为不需要传递 Context,也会出错。默认情况下是传递一个 Context
;只有当您有充分的理由说明另一种方法是错误的时,才直接使用 context.Background()
。
不要向结构体类型添加 Context
成员,相反,为需要传递 context
的类型上的每个方法添加一个 context
参数。唯一的例外是那些签名必须与标准库或第三方库中的接口匹配的方法。
不要在函数签名中创建自定义的 context
类型或使用 context
以外的接口。
如果你有应用程序数据要传递,把它放在返回参数、返回的对象,全局变量,或者 context
的值中。
context
是不可变的,所以将相同的 context
传递给相同的 deadline、cancellation signal、credentials、parent trace 等的多个调用也是可以的。
Copying(慎用)
为了避免意外的别名,从另一个包复制结构时要小心。
例如,bytes.Buffer
类型包含一个字节切片。如果复制 Buffer
,则复制中的切片可能会在原始数组中使用别名,从而导致后续的方法调用产生惊人的效果。
通常,如果 T 类型的值的方法与指针类型 *T 相关联,则不要复制它。
Crypto Rand
不要使用包 math/rand
来生成密钥,即使是一次性密钥。如果没有种子,生成器是完全可预测的。以 time.Nanoseconds()
为种子,只存在少量的熵。
相反,使用 crypto/rand
的 Reader,如果你需要文本,打印为十六进制或base64:
import ( "crypto/rand" // "encoding/base64" // "encoding/hex" "fmt" ) func Key() string { buf := make([]byte, 16) _, err := rand.Read(buf) if err != nil { panic(err) // out of randomness, should never happen } return fmt.Sprintf("%x", buf) // or hex.EncodeToString(buf) // or base64.StdEncoding.EncodeToString(buf) }
Declaring Empty Slices
当定义一个空切片时,首选:
var t []string
其次:
t := []string{}
前者声明一个 nil
切片,而后者是非 nil
但长度为零。它们在功能上是等价的——它们的 len
和 cap
都是0——但是nil切片是首选的方式。
注意,在有限的情况下,非 nil
但零长度的切片是首选的,例如编码 JSON
对象时( nil
切片编码为 null
,而 []string{}
编码为 JSON数组[])。
在设计接口时,避免区分 空切片
和 非空切片
、零长度切片
,因为这可能会导致微妙的编程错误。
如果是知道切片的长度,则最好在声明时也将 len 以及 cap 也定义上:
t := make([]string, 10, 10)
GopherCon 2016: Francesc Campoy - Understanding nil
Doc Comments
所有顶级的、导出的名称都应该有文档注释,非普通的未导出类型或函数声明也应该有。
Effective Go
Don't Panic
不要在正常的错误处理中使用 panic
。使用错误和多个返回值。
Effective Go
Error Strings
错误字符串不应该大写(除非以专有名词或首字母缩写开头)或以标点符号结尾,因为它们通常是在其他上下文之后打印的。
也就是说,使用 fmt.Errorf(“something bad”)
而不是 fmt.Errorf("Something bad")
,所以 log.Printf("Reading %s: %v", filename, err)
格式中没有假的大写字母。这不适用于日志记录,日志记录是隐式的面向行的,不会在其他消息中组合。