Effective Go 要点速记

1. 代码格式
运行 gofmt
工具进行 go 代码的标准格式化,vs code 可以自己运行具体配置参考:Go with Visual Studio Code。
几个 go 代码格式习惯:
- Indentation,go 采用 Tab 进行缩紧,除非必要的时候才使用空格;
- line length,go 没有行长度限制,如果行太长为了可读性可以 Tab 缩进将其包起来;
- parentheses,go 少用括号包括 for、if、switch 等,另外操作符优先级通过空格长短控制,如
x<<8 + y<<16
2. 代码注释
- 块注释:
/* */
- 行注释:
//
- 所有代码之前的没有换行的注释被认为是文档自声明,例如
/* Copyright 2023 Alibaba.Inc */
3. 命名
3.1 package 命名
通常 package 名是小写字母、单字名、不采用下划线和大小写混合。由于 package name 的存在,我们在命名导出成员(exported names)的时候有一些注意点:
- 例如 package 导出的 reader 类型,命名为 Reader 就比较清晰简洁不需要 BufReader,因为在引用的时候是 bufio.Reader 这样就清晰的表达了,
bufio.BufReader
就略显重复; - 例如 package 导出的构造函数命名,以 ring 包的构造函数为例
ring.NewRing()
、ring.Ring()
,、ring.New()
,New 命名就清晰简洁的;
3.2 getter&setter 命名
go 没有 getter,setter 装饰器,以 obj.Owner
为例,通常会有类似 SetOwner 和 GetOwner,但是以根据命名清晰简洁的原则可以命名为:obj.Owner(), obj.SetOwner()
。
3.3 interface 命名
- 只有一个 method 的 interface 的命名可以是
method name + "er"
,例如 Reader - 采用规范、有特殊含义的命名,例如 Read, Write, Close, Flush, String 等
4. 分号
go 不像 C 那样需要分号作为分隔,由此带来的问题 if、for、switch、select 这种控制结构的括号不能换行:
5. 控制结构
5.1 if
5.2 for
5.3 switch
6. 函数
6.1 多返回值
6.2 返回值命名
6.3 defer
7. 数据
7.1 new
new 给分配内存但是不做初始化,new(T)
为类型 T 的变量分配全0的存储空间并返回其地址,返回类型是 *T
。
7.2 make
make 为特性类型做初始化,它们包括:map、slice、channel,make 初始化的内存不是全0,返回的类型是 T
。
7.3 array
go array 就是一个固定长度的 slice,go 的数组与 c 的数组有几点区别:
- Arrays are values. Assigning one array to another copies all the elements.
- In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it.
- The size of an array is part of its type. The types
[10]int
and[20]int
are distinct.
7.4 slice
切片包装阵列可为数据序列提供更通用,功能强大和方便的接口。除了具有明确维度(例如变换矩阵)的项目外,Go 中的大多数数组编程都是用切片而不是简单的数组完成的。
7.5 two-dimensional slice
7.6 maps
Maps are a convenient and powerful built-in data structure that associate values of one type (the key) with values of another type (the element or value).
7.7 print
7.8 append
append 函数原型:
8. 初始化
8.1 constant
Go 中使用 iota
进行枚举的自动初始化创建:
8.2 vars
8.3 init 函数
每个源码文件都可以定义一个 init 函数,init 函数没有参数(niladic init function)。另外一个关键点 init 函数的执行时机:在包中的所有变量声明都对其初始化器求值之后调用Init,并且只有在所有导入的包都初始化之后才对这些初始化器求值。
9. 方法
9.1 指针与值
Go 默认是值传递,除了指针和 interface。
9.2 interface
interface 在 Go 用来为某个对象 object 指定行为。
9.3 类型转换
10. blank identifier
blank identifier 可以是任意类型任意值。
11. embedding
12. concurrency
12.1 goroutine
12.2 channel
12.3 channels of channels
12.4 并行
12.5 buffer 泄漏
13. Error
13.1 error
error built-in interface:
所以开发者可以实现自定义 Error 从而提供非常详细的错误信息,例如 os.PathError
:
13.2 panic
当程序运行时遇到不可恢复的错误时,go 提供了一个内置函数 panic
用于创建一个运行时错误同时终止程序的运行。
13.3 recover
上一节中提到的 panic
被调用之后会立刻终止程序执行,并且开始释放 goroutine 栈并且执行 defer
函数直到栈顶之后程序就结束运行了。在这个过程中可以尝试使用内置的 recover 函数来重新获取 goroutine 的控制权从而恢复正常的运行。
Public discussion