go规范

1 . 多个 if 语句可以折叠成 switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// NOT BAD
if foo() {
// ...
} else if bar == baz {
// ...
} else {
// ...
}

// BETTER
switch {
case foo():
// ...
case bar == baz:
// ...
default:
// ...
}

2 . 用 chan struct{} 来传递信号, chan bool 表达的不够清楚

当你在结构中看到 chan bool 的定义时,有时不容易理解如何使用该值,例如:

1
2
3
type Service struct {
deleteCh chan bool // what does this bool mean?
}

但是我们可以将其改为明确的 chan struct {} 来使其更清楚:我们不在乎值(它始终是 struct {}),我们关心可能发生的事件,例如:

1
2
3
type Service struct {
deleteCh chan struct{} // ok, if event than delete something.
}

3 . time.Second 比 time.Duration(30) * time.Second 更好

你不需要将无类型的常量包装成类型,编译器会找出来。
另外最好将常量移到第一位:

1
2
3
4
5
// BAD
delay := time.Second * 60 * 24 * 60

// GOOD
delay := 24 * 60 * 60 * time.Second

4 . 用 time.Duration 代替 int64 + 变量名

1
2
3
4
5
// BAD
var delayMillis int64 = 15000

// GOOD
var delay time.Duration = 15 * time.Second

5. 按类型分组 const 声明,按逻辑和/或类型分组 var

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// BAD
const (
foo = 1
bar = 2
message = "warn message"
)

// MOSTLY BAD
const foo = 1
const bar = 2
const message = "warn message"

// GOOD
const (
foo = 1
bar = 2
)

const message = "warn message"

6 要比较时间戳,请使用 time.Before 或 time.After ,不要使用 time.Sub 来获得 duration (持续时间),然后检查它的值。

7. 用 %+v 来打印数据的比较全的信息

8. 在 Go 里面要小心使用 range

1
2
for i := range a and for i, v := range &a ,都不是 a 的副本
但是 for i, v := range a 里面的就是 a 的副本

9. 不要忘记停止 ticker

1
2
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

10.所有代码都应该通过golint和go vet的检查并无错误。

11. 零值 sync.Mutex 和 sync.RWMutex 是有效的。所以指向 mutex 的指针基本是不必要的。

1
2
var mu sync.Mutex
mu.Lock()

12. Channel 的 size 要么是 1,要么是无缓冲的

1
2
c := make(chan int, 1)
c := make(chan int)

13. 枚举从 1 开始

1
2
3
4
5
6
7
type Operation int

const (
Add Operation = iota + 1
Subtract
Multiply
)

14. 使用 time.Time 表达瞬时时间

在处理时间的瞬间时使用 [time.Time](https://golang.org/pkg/time/#Time),在比较、添加或减去时间时使用 time.Time 中的方法。

1
2
3
func isActive(now, start, stop time.Time) bool {
return (start.Before(now) || start.Equal(now)) && now.Before(stop)
}

15. 在尽可能的情况下,在初始化要追加的切片时为make()提供一个容量值。

16. 优先使用 strconv 而不是 fmt

17. 包命名

  • 全部小写。没有大写或下划线。
  • 大多数使用命名导入的情况下,不需要重命名。
  • 简短而简洁。请记住,在每个使用的地方都完整标识了该名称。
  • 不用复数。例如net/url,而不是net/urls
  • 不要用“common”,“util”,“shared”或“lib”。这些是不好的,信息量不足的名称。

18. 嵌入式类型(例如 mutex)应位于结构体内的字段列表的顶部,并且必须有一个空行将嵌入式字段与常规字段分隔开。

19. 不应明确返回长度为零的切片。应该返回nil 来代替。

20. 要检查切片是否为空,请始终使用len(s) == 0。而非 nil

21. time.After() 在某些情况下会发生泄露,替换为使用 Timer。

22. 读写磁盘时,使用读写 buffer。

23. 内存分配复用内存可以使用 sync.Pool

24. 频繁的字符串拼接操作(+=),替换为 StringBuffer 或 StringBuilder

25. 并发检测 race

分享到 评论