1、干净与强迫症
Go在代码干净上有了近乎苛刻的要求,主要体现在如下几个方面:
- 编译器不能通过未使用的局部变量(包括未使用的标签)。
- “import”未使用的包同样通不过编译。
- 所有的控制结构、函数和方法定义的“(”放到行尾,而不能另起一行。
- 提供go fmt工具格式化代码,使所有的代码风格保持统一。
Go对代码的干净和整洁要求到了强迫症的程度,但这是一种好的约束,虽然很多人难以接
受。
2、comma,ok表达式
- 获取map值。
获取map中不存在键的值不会发生异常,而是会返回值类型的零值,如果想确定map中是否存在key,则可以使用获取map值的comma,ok语法。示例如下:
m := make(map[string]string)
v,ok := m["some"]
//通过ok进行判断
if !ok {
println ("m[some]is nil")
else
println ("m[some]="v)
}
- 读取chan的值
读取已经关闭的通道,不会阻塞,也不会引起panic,而是一直返回该通道的零值。怎么判断通道已经关闭?有两种方法,一种是读取通道的comma,ok表达式,如果通道已经关闭,则ok的返回值是fasle,另一种就是通过range循环迭代。示例如下:
c := make(chan int)
go func(){
c<-1
c<-2
close(c)
}()
for {
//使用comma,ok判断通道是否关闭
v,ok :<-c
if ok {
printIn (v)
} else
break
}
}
//使用range更加简洁
for v := range c {
println (v)
}
- 类型断言(type assertion)
接口断言通常可以使用comma,ok语句来确定接口是否绑定某个实例类型,或者判断接口绑定的实例类型是否实现另一个接口。示例如下:
//如下代码片段摘自标准包src/net/http/request.go
//判断接口body绑定的实例是否实现了另一个接口类型io.ReadCloser
783 rc,ok := body.(io.Readcloser)
//判断接口Body绑定的实例类型是否是*maxBytesReader具体类型
1107 if,ok :r.Body.(*maxBytesReader);!ok {
3、简写模式
G0语言很多重复的引用或声明可以用“()”进行简写。
- import多个包。例如:
//推荐写法
import (
"bufio"
"bytes"
)
//不推荐写法
import "bufio"
import "bytes"
- 多个变量声明。
包中多个相关全局变量声明时,建议使用“()”进行合并声明。示例如下:
//推荐这样的写法
var (
bufioReaderPool
sync.Pool
bufioWriter2kPool sync.Pool
bufioWriter4kPool sync.Pool
)
//不推荐这样的写法
var bufioReaderPool sync.Pool
var bufioWriter2kPool sync.Pool
var bufioWriter4kPool sync.Pool
4、包中的函数或方法设计
很多包的开发者会在内部实现两个“同名”的函数或方法,一个首字母大写,用于导出API供外部调用;一个首字母小写,用于实现具体逻辑。一般首字母大写的函数调用首字母小写的函数,同时包装一些功能;首字母小写的函数负责更多的底层细节。
大部分情况下我们不需要两个同名且只是首字母大小写不同的函数,只有在函数逻辑很复杂,而且函数在包的内、外部都被调用的情况下,才考虑拆分为两个函数进行实现。一方面减少单个函数的复杂性,另一方面进行调用隔离。这种编程技术在标准库database/sql里面体现得最明显。
5、多值返回函数
多值返回函数里如果有eror或bool类型的返回值,则应该将eror或bool作为最后一个返回值。这是一种编程风格,没有对错。Go标准库的写法也遵循这样的规则。当绝大多数人都遵照这种写法时,如果不遵循这种“潜规则”,则写出的代码让别人读起来很别扭。示例如下:
//分析标准库bytes的代码可以看到这种习惯用法
//cd $GOROOT/src/bytes/&&egrep 'func.*error\)Ifunc.*bool\)'-r -nIgrep -v 'test!
buffer.go:107:func (b *Buffer)tryGrowByReslice(n int)(int,bool){
buffer.go:335:func (b *Buffer)ReadByte()(byte,error){
reader.go:66:func (r *Reader)ReadByte()(byte,error){
reader.go:113:func (r *Reader)Seek(offset int64,whence int)(int64,error)