变量声明的最佳实践
这是一个细节篇。在Go中,推崇“做一件事只用一种办法”,比如说循环只用for一种声明形式,但变量的声明好像却有点与之违背的意思,我们可以有很大的灵活性去进行变量的声明。
基本上来说每个程序都需要进行变量声明,首先来看一下变量的声明形式:
声明形式
需要注意与其他主流静态语言的不同是Go将变量名放在了类型的前面。
这是单独声明的变量,还可以在一行中进行多变量的声明:
var a, b, c int = 5, 6, 7
还可以使用变量声明块(block)的语法形式:当然,在变量声明块中也能进行一行多变量的声明
var (
a, b, c int = 5, 6, 7
s string = "hello"
t bool = true
)
两种变量声明语法糖
再来说一下两种变量的语法糖:
- 省略类型信息的声明
类似于这样子:var b = 13,省略变量声明的类型信息,这个也容易理解,就是自动类型推断,会根据右侧变量初值自动推导出变量的类型,并给这个变量赋予初值所对应的默认类型。需要注意默认类型,比如当我们不想要这个默认类型,就需要显示类型转换变成我们想要的类型,举个例子正形的默认类型是int,我们想要int8的话, var b = int8(13)。这种语法糖适用条件当然就是变量声明的同时有进行赋值,才能进行推断。
- 短变量的声明
这是Go语言中的特色,很适合在局部变量中进行声明使用。类似于下面这样的语法:
a := 12
b := 'A'
c := "hello"
这种声明方式连var关键字都给省略了。当然也要注意适用条件:在局部变量进行声明适用,包级变量的声明不能适用这种方式。只能使用带var关键字的声明方式
那我们该怎么进行变量的声明呢,该使用给的语法糖吗?
如何更好地声明变量
首先,变量的声明离不开两类,一类就是包级变量的声明,一类就是局部变量的声明。
那么就依次来看:
包级变量的声明:
- 声明但延迟初始化
这种时候就不能省略变量的类型信息了,但是即便延迟初始化了,这些变量都有初始的“零值”。
- 声明同时进行初始化
如果包级在声明的同时进行了初始化,推荐使用第一种语法糖的形式。
var ErrShortWrite = errors.New("short write")
var ErrShortBuffer = errors.New("short buffer")
var EOF = errors.New("EOF")
比如标准库中io包对包级变量声明的同时显示初始化了就使用这种方式。
var a int32
局部变量的声明:
- 声明但延迟初始化
同样也不能省略变量的类型信息,使用通用的声明形式。
- 声明同时进行初始化
这个时候推荐使用第二种语法糖的形式,短变量的声明形式是局部变量最常用的方式了。同时这种声明形式经常会和分支控制一起使用。在分支控制语句我们很少在外面声明分支控制语句中的变量。类似于这样:
if as, isASCII := makeASCIISet(chars); isASCII {
for i := len(s) - 1; i >= 0; i-- {
if as.contains(s[i]) {
return i
}
}
return -1
}
变量声明的两种原则
1.聚类原则
前面我们也提到了变量代码块,通常,我们会将同一类的变量声明放在一个 var 变量声明块中,不同类的声明放在不同的 var 声明块中,比如下面就是从标准库net包中摘取的两段变量声明代码:
var (
netGo bool
netCgo bool
)
var (
aLongTimeAgo = time.Unix(1, 0)
noDeadline = time.Time{}
noCancel = (chan struct{})(nil)
)
同时也可以聚类理解为:我们将延迟初始化的变量声明放在一个 var 声明块 (比如上面的第一个 var 声明块),然后将声明且显式初始化的变量放在另一个 var 块中(比如上面的第二个 var 声明块)
2.就近原则
而就近原则则是说我们尽可能在靠近第一次使用变量的位置声明这个变量。就近原则实际上也是对变量的作用域最小化的一种实现手段。
我们要根据情况判断要不要使用代码块在文件头部声明:如果一个包级变量在包内部被多处使用,那么这个变量还是放在源文件头部声明比较适合的。
总结图
一张总结图进行文章的总结(当然不是我画的)
转载自:https://juejin.cn/post/7232268434998050877