小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
总结了一些Go语言在日常开发中,需要注意到的编码规范问题。
代码风格
当函数中需要使用到多个变量时,可以在函数开始处使用 var 声明。在函数外部声明必须使用 var ,不要采用 := ,容易踩到变量的作用域的问题。
var (
Width int
Height int
)
在初始化结构引用时,请使用 &T{}代替 new(T),以使其与结构体初始化一致。
// bad
sptr := new(T)
sptr.Name = "bar"
// good
sptr := &T{Name: "bar"}
尽可能指定容器容量,以便为容器预先分配内存,例如:
v := make(map[int]string, 4)
v := make([]string, 0, 4)
如果需要在 if 之外使用函数调用的结果,则应采用下面的方式。
// bad
if v, err := foo(); err != nil {
// error handling
}
// good
v, err := foo()
if err != nil {
// error handling
}
类型
空字符串判断。
// bad
if s == "" {
// normal code
}
// good
if len(s) == 0 {
// normal code
}
字符串是否包含子串或字符。
// bad
strings.Contains(s, subStr)
strings.ContainsAny(s, char)
strings.ContainRune(s, r)
// good
strings.Index(s, subStr) > -1
strings.IndexAny(s, char) > -1
strings.IndexRune(s, r) > -1
空 slice 判断。上面判断同样适用于 map、channel。
// bad
if len(slice) = 0 {
// normal code
}
// good
if slice != nil && len(slice) == 0 {
// normal code
}
声明slice。
// bad
s := []string{}
s := make([]string, 0)
// good
var s []string
控制结构
不要在 for 循环里面使用 defer,defer 只有在函数退出时才会执行。
// bad
for file := range files {
fd, err := os.Open(file)
if err != nil {
return err
}
defer fd.Close()
// normal code
}
// good
for file := range files {
func() {
fd, err := os.Open(file)
if err != nil {
return err
}
defer fd.Close()
// normal code
}()
}
最佳实践
append 要小心自动分配内存,append 返回的可能是新分配的地址。
如果要直接修改 map 的 value 值,则 value 只能是指针,否则要覆盖原来的值。
map 在并发中需要加锁。
编译过程无法检查 interface{} 的转换,只能在运行时检查,小心引起 panic。