计算机科学中只有两件难事:缓存失效和命名。 ——Phil Karlton,Netscape架构师

Go命名一般遵循两个原则:

  • 简单且一致
  • 利用上下文辅助命名

    简单且一致

  • 能用一个单词就不用单词组合

  • 能用单个字母(特定上下文中)表达标识符,就不用完整的单词

    包命名

    1、一般建议以单个单词命名,Go 标准库就是这样做的
    2、给包命名时,不仅要考虑包自身的名字,也要兼顾包导出标识符(如变量、常量、类型、函数等)的命名,由于对这些包导出标识符的引用须以包名为前缀,因此对包导出标识符的命名中就不要再出现包名。比如:

    1. strings.Reader [好的方式]
    2. strings.StringReader [坏的方式,重复string表示]

    变量、类型、函数和方法的命名

    1、为变量、类型、函数和方法命名时,尽量以简单、短小为首要原则
    2、变量名由一个以上单词组合构成时,使用驼峰命名法,只在包内使用的变量使用“小驼峰拼写法”(lowerCamelCase),需要导出的变量使用“大驼峰拼写法”(UpperCamelCase)
    3、缩略词首字母是大写的,那么其他字母也保持大写,比如HTTP(Hypertext Transfer Protocol)
    4、从Go标准库代码来看,不同类别的标识符命名呈现以下特征:

  • 循环和条件变量多采用单个字母命名

  • 函数/方法的参数和返回值以单个单词和单个字母为主
  • 函数和类型以多个单词的复合词进行命名

5、常用命名惯例:
(1)变量名字中不要带有类型的信息,比如:

  1. userSlice []*User [坏的方式]
  2. users []*User [好的方式]

保持变量声明与使用之间的距离越近越好,或者第一次使用变量之前声明该变量。

(2)保持简短命名变量含义上的一致性
Go语言中有大量的单字母、单个词或者缩写命名的简短变量,可能会觉得简短命名会降低代码的可读性,但 Go 语言中建议通过保持一致性来维持可读性。

一致意味着代码中相同或相似的命名传达的含义是相同或相似的,这样便于代码阅读者或者维护者猜测出变量的用途。

变量 v、k、i 的常用含义:

  1. for i, v := range s{} // i 为下标;v 为元素
  2. for k, v := range m{} // k 为key,v为元素

常量

常量在命名方式上与变量无较大差别,并不要求全部大写(与C语言不一样)。对于名称本身就是全大写的特定常量使用全大写的名字,如数学计算中的 PI ,或是为与系统信号名称保持一致而使用全大写。

  1. // $GOROOT/src/net/http/request.go
  2. const(
  3. defaultMaxMemory = 32 << 20 // 32M
  4. )
  5. // $GOROOT/src/math/sin.go
  6. const(
  7. PI4A = 7.8............
  8. )
  9. // 信号
  10. const(
  11. SIGABRT = Signal(0x6)
  12. )

接口

对于接口类型,优先以单个单词命名,对于拥有唯一方法或者通过多个拥有唯一方法的接口组合而成的接口,Go语言的惯例是用“方法名 + er”命名。比如:

  1. type Writer interface {
  2. Write(p []byte) (n int, err error)
  3. }
  4. type Reader interface{
  5. Read(p []btye) (n int, err error)
  6. }
  7. type ReadWriteCloser interface {
  8. Reader
  9. Writer
  10. }

利用上下文环境,让最短的名字携带足够多的信息

Go 在给标识命名时还需考虑上下文的环境,即在不影响可读性的前提下,兼顾一致性原则,尽可能地用短小的名字命名,这与一些主流的语言在命名上的建议有所不同。

  1. for index := 0; index < len(s); index++ {
  2. value := s[index]
  3. }
  4. for i := 0; i < len(s); i++ {
  5. v := s[i]
  6. }

从 for 循环这个上下文中,index、value 携带的信息不比 i、v多。下面再来看一个对比:

  1. // 不好的命名
  2. func RuneCount(buffer []byte) int {
  3. runeCount := 0
  4. for index := 0; index < len(buffer); {
  5. if buffer[index] < RuneSelf {
  6. index++
  7. } else {
  8. _, size := DecodeRune(buffer[index:])
  9. index += size
  10. }
  11. runeCount++
  12. }
  13. return runeCount
  14. }
  15. // 好的命名
  16. func RuneCount(b []byte) int {
  17. count := 0
  18. for i := 0; i < len(b); {
  19. if b[i] < RuneSelf {
  20. i++
  21. } else {
  22. _, n := DecodeRune(b[i:])
  23. i += n
  24. }
  25. count++
  26. }
  27. return count
  28. }