小知识2:Go语言编码规范

208 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

总结了一些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。