Uber的Go语言指南

1.接口实质上在底层用两个字段表示:
一个指向某些特定类型信息的指针。您可以将其视为"type"。
数据指针。如果存储的数据是指针,则直接存储。如果存储的数据是一个值,则存储指向该值的指针。
如果希望接口方法修改基础数据,则必须使用指针传递。

2.使用值接收器的方法既可以通过值调用,也可以通过指针调用。

值接收器实现的接口,值和指针都可用。
指针接收器实现的接口,只能指针可用,值会编译失败。

3.零值Mutex是有效的,(sync.Mutex RWMutex),
所以var my sync.Mutex是可以使用的 。
而mu:=new(sync.Mutex)是没有必要的。

4.slices和maps包含了指向底层数据的指针。
当我们要给一个变量赋值map或slice时,且不想受到复制者之后修改的影响,应该使用copy:
s1:=…
s2:=…
copy(s2,s1)
s1[0]=123
此时s1的修改不会影响s2

map也亦然
result := make(map[string]int, len(s.counters))
for k, v := range s.counters {
result[k] = v
}
5.返回 slices 或 maps同上

6.defer的作用
Defer 的开销非常小,只有在您可以证明函数执行时间处于纳秒级的程度时,才应避免这样做。使用 defer 提升可读性是值得的,因为使用它们的成本微不足道。尤其适用于那些不仅仅是简单内存访问的较大的方法,在这些方法中其他计算的资源消耗远超过 defer。

7.channel的size需要界定通道边界,竞态条件,以及逻辑上下文梳理

8.由于变量的默认值为 0,因此通常应以非零值开头枚举。
const (
Add Operation = iota + 1
Subtract
Multiply
)
在某些情况下,使用零值是有意义的(枚举从零开始),例如,当零值是理想的默认行为时。

9.使用 time.Time 表达瞬时时间
func isActive(now, start, stop time.Time) bool {
return (start.Before(now) || start.Equal(now)) && now.Before(stop)
}

10.使用 time.Duration 表达时间段
func poll(delay time.Duration) {
for {
// …
time.Sleep(delay)
}
}
poll(10*time.Second)

如果我们想要下一个日历日(当前天的下一天)的同一个时间点,我们应该使用 Time.AddDate。但是,如果我们想保证某一时刻比前一时刻晚 24 小时,我们应该使用 Time.Add。

newDay := t.AddDate(0 /* years /, 0, / months /, 1 / days */)
maybeNewDay := t.Add(24 * time.Hour)
对外部系统使用 time.Time 和 time.Duration
尽可能在与外部系统的交互中使用 time.Duration 和 time.Time 例如 :

Command-line 标志: flag 通过 time.ParseDuration 支持 time.Duration
JSON: encoding/json 通过其 UnmarshalJSON method 方法支持将 time.Time 编码为 RFC 3339 字符串
SQL: database/sql 支持将 DATETIME 或 TIMESTAMP 列转换为 time.Time,如果底层驱动程序支持则返回
YAML: gopkg.in/yaml.v2 支持将 time.Time 作为 RFC 3339 字符串,并通过 time.ParseDuration 支持 time.Duration。
当不能在这些交互中使用 time.Duration 时,请使用 int 或 float64,并在字段名称中包含单位。

例如,由于 encoding/json 不支持 time.Duration,因此该单位包含在字段的名称中。
// {“intervalMillis”: 2000}
type Config struct {
IntervalMillis int json:"intervalMillis"
}

10.如果客户端需要检测错误,并且您已使用创建了一个简单的错误 errors.

11.处理断言失败
t, ok := i.(string)
if !ok {
// 优雅地处理错误
}

12.在生产环境中运行的代码必须避免出现 panic。
即使在测试代码中,也优先使用t.Fatal或者t.FailNow而不是 panic 来确保失败被标记。

13.避免可变全局变量


性能优化
1.优先使用 strconv 而不是 fmt
将原语转换为字符串或从字符串转换时,strconv速度比fmt快。

2.避免字符串到字节的转换
data := []byte(“Hello world”)
for i := 0; i < b.N; i++ {
w.Write(data)
}

3.在尽可能的情况下,在使用 make() 初始化的时候提供容量信息
make(map[T1]T2, hint)
m 是在没有大小提示的情况下创建的; 在运行时可能会有更多分配。
m 是有大小提示创建的;在运行时可能会有更少的分配。


规范

1.一致性

2.相似的声明放在一组
import (
“a”
“b”
)
const (
a = 1
b = 2
)

var (
a = 1
b = 2
)

type (
Area float64
Volume float64
)

3.包名
当命名包时,请按下面规则选择一个名称:

全部小写。没有大写或下划线。
大多数使用命名导入的情况下,不需要重命名。
简短而简洁。请记住,在每个使用的地方都完整标识了该名称。
不用复数。例如net/url,而不是net/urls。
不要用“common”,“util”,“shared”或“lib”。这些是不好的,信息量不足的名称。
4.函数
函数按接收者分组的,普通工具函数应在文件末尾出现

5.减少嵌套
代码应通过尽可能先处理错误情况/特殊情况并尽早返回或继续循环来减少嵌套。减少嵌套多个级别的代码的代码量。

6.不必要的 else
如果在 if 的两个分支中都设置了变量,则可以将其替换为单个 if。

  1. 对于未导出的顶层常量和变量,使用_作为前缀
    在未导出的顶级vars和consts, 前面加上前缀_,以使它们在使用时明确表示它们是全局符号。
    未导出的错误值,应以err开头。

8.使用字段名初始化结构体
k := User{
FirstName: “John”,
LastName: “Doe”,
Admin: true,
}

  1. 如果将变量明确设置为某个值,则应使用短变量声明形式 (:=)。

10.nil 是一个有效的 slice
if x == “” {
return nil
}
要检查切片是否为空,请始终使用len(s) == 0。而非 nil。

11.零值切片(用var声明的切片)可立即使用,无需调用make()创建。
var nums []int
nums = append(nums, 1)

12.map初始化
var (
// m1 读写安全;
// m2 在写入时会 panic
m1 = make(map[T1]T2)
m2 map[T1]T2
)

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值