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
)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章