《Go语言精进之路》读书笔记 | 使用Go命名惯例对标识符进行命名

Posted COCOgsta

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Go语言精进之路》读书笔记 | 使用Go命名惯例对标识符进行命名相关的知识,希望对你有一定的参考价值。

书籍来源:《Go语言精进之路:从新手到高手的编程思想、方法和技巧》

一边学习一边整理读书笔记,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:《Go语言精进之路》读书笔记 | 汇总_COCOgsta的博客-CSDN博客


从编程语言诞生那天起,给标识符命名这件事就一直伴随着程序员。命名看似简单,但在如今大规模软件工程需要程序员个体间紧密协作的背景下,给出好的命名并非易事。

Go及其标准库的实现是Go命名惯例形成的源头,因此如果要寻找良好命名的示范,Go标准库是一个不错的地方。

要想做好Go标识符的命名(包括对包的命名),至少要遵循两个原则:简单且一致;利用上下文辅助命名。

7.1 简单且一致

下面是Go语言中一些常见类别标识符的命名惯例。

对于Go中的包(package),一般建议以小写形式的单个单词命名。

我们在给包命名时不要有是否与其他包重名的顾虑,因为在Go中,包名可以不唯一。可以在导入包时使用一个显式包名来指代导入的包,并且在这个源文件中使用这个显式包名来引用包中的元素,示例如下。

import "github.com/bigwhite/foo/log"             // log.XX中的log指代github.com/ bigwhite/foo/log下的包
import barlog "github.com/bigwhite/bar/log"      // barlog这个显式包名指代github.com/ bigwhite/bar/log下的包
复制代码

Go语言建议,包名应尽量与包导入路径(import path)的最后一个路径分段保持一致。比如:包导入路径golang.org/x/text/encoding的最后路径分段是encoding,该路径下包名就应该为encoding。

此外,对包导出标识符命名时,在名字中不要再包含包名,比如:

strings.Reader              [good]
strings.StringReader        [bad]
strings.NewReader           [good]
strings.NewStringReader     [bad]

bytes.Buffer                [good]
bytes.ByteBuffer            [bad]
bytes.NewBuffer             [good]
bytes.NewByteBuffer         [bad]
复制代码
  1. 变量、类型、函数和方法

在Go中变量分为包级别的变量和局部变量(函数或方法内的变量)。函数或方法的参数、返回值都可以被视为局部变量。

Go语言官方要求标识符命名采用驼峰命名法,最常见的标识符命名法是“小骆峰拼写法”。

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

函数/方法的参数和返回值变量以单个单词或单个字母为主;

函数多以多单词的复合词进行命名;

类型多以多单词的复合词进行命名。

除了上述特征,还有一些在命名时常用的惯例。

(1)变量名字中不要带有类型信息

比如以下命名:

userSlice []*User         [bad]
users     []*User         [good]
复制代码

(2)保持简短命名变量含义上的一致性

简短命名变量建议通过保持一致性来维持可读性。一致意味着代码中相同或相似的命名所传达的含义是相同或相似的,这样便于代码阅读者或维护者猜测出变量的用途。

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

// 循环语句中的变量
for i, v := range s  ...            // i为下标变量; v为元素值
for k, v := range m  ...            // k为key变量; v为元素值
for v := range r  // channel ...    // v为元素值

// if、switch/case分支语句中的变量
if v := mimeTypes[ext]; v != ""     // v: 元素值
switch v := ptr.Elem(); v.Kind() 
    ...


case v := <-c:                        // v: 元素值

// 反射的结果值
v := reflect.ValueOf(x)
复制代码

变量t的常用含义:

t := time.Now()                            // 时间
t := &Timer                              // 定时器
if t := md.typemap[off]; t != nil        // 类型
复制代码

变量b的常用含义:

b := make([]byte, n)                       // byte切片
b := new(bytes.Buffer)                     // byte缓存
复制代码
  1. 常量

常量多使用多单词组合的方式命名。

当然,可以对名称本身就是全大写的特定常量使用全大写的名字,比如数学计算中的PI,或是为了与系统错误码、系统信号名称保持一致而用全大写方式命名

在Go中数值型常量无须显式赋予类型,常量会在使用时根据左值类型和其他运算操作数的类型进行自动转换。

  1. 接口

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

// $GOROOT/src/io/io.go

type Writer interface 
    Write(p []byte) (n int, err error)


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


type Closer interface 
    Close() error


type ReadWriteCloser interface 
    Reader
    Writer
    Closer

复制代码

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

Go在给标识符命名时还有着考虑上下文环境的惯例,即在不影响可读性的前提下,兼顾一致性原则,尽可能地用短小的名字命名标识符。

我们在Go代码中来分别运用这两个命名方案并做比对:

for index := 0; index < len(s); index++ 
    value := s[index]
    ...


// vs

for i := 0; i < len(s); i++ 
    v := s[i]
    ...

复制代码

我们看到,至少在for循环这个上下文中,index、value携带的信息并不比i、v多。

以上是关于《Go语言精进之路》读书笔记 | 使用Go命名惯例对标识符进行命名的主要内容,如果未能解决你的问题,请参考以下文章

《Go语言精进之路,从新手到高手的编程思想方法和技巧1》读书笔记和分享

《Go语言精进之路,从新手到高手的编程思想方法和技巧1》读书笔记和分享

《Go语言精进之路》读书笔记 | 使用Go语言原生编码思维来写Go代码

《Go语言精进之路》读书笔记 | 使用Go语言原生编码思维来写Go代码

《Go语言精进之路》读书笔记 | 使用一致的变量声明形式

《Go语言精进之路》读书笔记 | 使用无类型常量简化代码