Home

(译)Go naming conventions

本文的内容是Andrew Gerrand在Meetup Golang Paris上一次演讲slide的翻译(youtubeslide),内容是Go里面的一些命名的规范与建议。内容不错,在这里记录分享。

Names matter

可读性定义代码的质量。

好的命名对可读性非常重要。

好的命名是:

A rule of thumb

一个常用的经验法则是:一个命名声明与使用的地方的距离越大,那么这个名字应该越长。

Use MixedCase

在Go应使用驼峰命名法(不要使用下划线命名)。

首字母应该大写,像ServeHTTPIDProcessor

Local variables

本地变量应保持简短,长短命名将有碍阅读。

例如一些常用的约定: 使用 i 表示索引。 使用 r 表示reader。

长命名可能对于很长的函数或有很对本地变量的函数很有用,但那通常表示你的代码需要重构了。

坏🌰

func RuneCount(buffer []byte) int {
    index, count := 0, 0
    for index < len(buffer) {
        if buffer[index] < RuneSelf {
            index++
        } else {
            _, size := DecodeRune(buffer[index:])
            index += size
        }
        count++
    }
    return count
}

好🌰

func RuneCount(b []byte) int {
    i, n := 0, 0
    for i < len(b) {
        if b[i] < RuneSelf {
            i++
        } else {
            _, size := DecodeRune(b[i:])
            i += size
        }
        n++
    }
    return n
}

参数

函数的参数作用像本地变量,但它们还具有文档的功能。

当参数类型具有描述性时,使用短命名。

func AfterFunc(d Duration, f func()) *Timer

func Escape(w io.Writer, s []byte)

当参数类型很模糊时(例如原生类型,相同的类型的参数时),那么参数名字需要像文档一样说明。

func Unix(sec, nsec int64) Time

func HasPrefix(s, prefix []byte) bool

返回值

对于一个对外发布的函数,返回值应命名应像文档一样说明返回值的作用。

好的例子:

func Copy(dst Writer, src Reader) (written int64, err error)

func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)

Receivers

Receivers是一种特殊类型的参数

通常情况,使用一到两个其类型简写的字符表示,因为在方法里面他们会经常出现

func (b *Buffer) Read(p []byte) (n int, err error)

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request)

func (r Rectangle) Size() Point

一个类型的方法Receiver命名应保持一致(不要在一个方法里面用r而在另一个方法里用rdr)

Exported package-level names

一个包的导出的名字被其包命修饰,时时铭记这一点。 所以在标准库里面有bytes.Bufferstrings.Reader,而不是bytes.ByteBuffer,strings.StringReader

接口类型

如果一个接口里面只有一个方法,那通常给方法名后面加一个’er’就好了。

type Reader interface {
    Read(p []byte) (n int, err error)
}

虽然有时英语语法上是不对的,但我们还是这么做(but we do it anyway)

type Execer interface {
    Exec(query string, args []Value) (Result, error)
}

有时要做一些转换看起来更好

type ByteReader interface {
    ReadByte() (c byte, err error)
}

但一个接口包含多个方法是,选择名字需要准确的描述这个借口的作用(例如: net.Conn, http.ResponseWriter, io.ReadWriter)

Error

错误类型命名类似FooError:

type ExitError struct {
    ...
}

错误值命名类似ErrFoo:

var ErrFormat = errors.New("image: unknown format")

包命名

对外发布的包名应该说明包的作用

避免使用util,common,等等

Import paths

包的最后一个部分的路径应和包名相同。

"compress/gzip" // package gzip

避免在包路径上结巴(233)。

"code.google.com/p/goauth2/oauth2" // bad; my fault

对于库来说,通常将代码放在根目录下。

"github.com/golang/oauth2" // package oauth2

避免大写字母(不是所有的文件系统都是大小写敏感的)。

标准库

文中许多例子都是来自标准库。

标准库是个寻找优秀Go代码的地方,常看常新。

但请记住:

When the standard library was written, we were still learning. Most of it we got right, but we made some mistakes.

Conclusion

Use short names. 使用短的名字

Think about context. 多思考上下文

Use your judgment. 要有自己的判断