欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Go你不得不知道的一些實(shí)用小技巧

 更新時(shí)間:2022年11月21日 11:32:48   作者:qi66  
開發(fā)語言上Go成為高并發(fā)業(yè)務(wù)開發(fā)的主流語言,再加上云原生技術(shù)底座的驅(qū)動,Go語言風(fēng)光無限,下面這篇文章主要給大家介紹了關(guān)于Go你不得不知道的一些實(shí)用小技巧,需要的朋友可以參考下

Go 箴言

  • 不要通過共享內(nèi)存進(jìn)行通信,通過通信共享內(nèi)存
  • 并發(fā)不是并行
  • 管道用于協(xié)調(diào);互斥量(鎖)用于同步
  • 接口越大,抽象就越弱
  • 利用好零值
  • 空接口 interface{} 沒有任何類型約束
  • Gofmt 的風(fēng)格不是人們最喜歡的,但 gofmt 是每個人的最愛
  • 允許一點(diǎn)點(diǎn)重復(fù)比引入一點(diǎn)點(diǎn)依賴更好
  • 系統(tǒng)調(diào)用必須始終使用構(gòu)建標(biāo)記進(jìn)行保護(hù)
  • 必須始終使用構(gòu)建標(biāo)記保護(hù) Cgo
  • Cgo 不是 Go
  • 使用標(biāo)準(zhǔn)庫的 unsafe 包,不能保證能如期運(yùn)行
  • 清晰比聰明更好
  • 反射永遠(yuǎn)不清晰
  • 錯誤是值
  • 不要只檢查錯誤,還要優(yōu)雅地處理它們
  • 設(shè)計(jì)架構(gòu),命名組件,(文檔)記錄細(xì)節(jié)
  • 文檔是供用戶使用的
  • 不要(在生產(chǎn)環(huán)境)使用 panic()

Go 之禪

  • 每個 package 實(shí)現(xiàn)單一的目的
  • 顯式處理錯誤
  • 盡早返回,而不是使用深嵌套
  • 讓調(diào)用者處理并發(fā)(帶來的問題)
  • 在啟動一個 goroutine 時(shí),需要知道何時(shí)它會停止
  • 避免 package 級別的狀態(tài)
  • 簡單很重要
  • 編寫測試以鎖定 package API 的行為
  • 如果你覺得慢,先編寫 benchmark 來證明
  • 適度是一種美德
  • 可維護(hù)性

代碼

使用 go fmt 格式化

讓團(tuán)隊(duì)一起使用官方的 Go 格式工具,不要重新發(fā)明輪子。

嘗試減少代碼復(fù)雜度。 這將幫助所有人使代碼易于閱讀。

多個 if 語句可以折疊成 switch

// NOT BAD
if foo() {
    // ...
} else if bar == baz {
    // ...
} else {
    // ...
}

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

用 chan struct{} 來傳遞信號, chan bool 表達(dá)的不夠清楚

當(dāng)你在結(jié)構(gòu)中看到 chan bool 的定義時(shí),有時(shí)不容易理解如何使用該值,例如:

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

但是我們可以將其改為明確的 chan struct {} 來使其更清楚:我們不在乎值(它始終是 struct {}),我們關(guān)心可能發(fā)生的事件,例如:

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

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

你不需要將無類型的常量包裝成類型,編譯器會找出來。

另外最好將常量移到第一位:

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

// VERY BAD
delay := 60 * time.Second * 60 * 24

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

用 time.Duration 代替 int64 + 變量名

// BAD
var delayMillis int64 = 15000

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

按類型分組 const 聲明,按邏輯和/或類型分組 var

// 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"

這個模式也適用于 var。

  • ** 每個阻塞或者 IO 函數(shù)操作應(yīng)該是可取消的或者至少是可超時(shí)的

  • ** 為整型常量值實(shí)現(xiàn) Stringer 接口

  • ** 檢查 defer 中的錯誤

  defer func() {
      err := ocp.Close()
      if err != nil {
          rerr = err
      }
  }()
  • ** 不要在 checkErr 函數(shù)中使用 panic() 或 os.Exit()

  • ** 僅僅在很特殊情況下才使用 panic, 你必須要去處理 error

  • ** 不要給枚舉使用別名,因?yàn)檫@打破了類型安全

  package main
  type Status = int
  type Format = int // remove `=` to have type safety

  const A Status = 1
  const B Format = 1

  func main() {
      println(A == B)
  }
  • **

    如果你想省略返回參數(shù),你最好表示出來

    • _ = f() 比 f() 更好
  • **

    我們用 a := []T{} 來簡單初始化 slice

  • **

    用 range 循環(huán)來進(jìn)行數(shù)組或 slice 的迭代

    • for _, c := range a[3:7] {...} 比 for i := 3; i < 7; i++ {...} 更好
  • **

    多行字符串用反引號(`)

  • **

    用 _ 來跳過不用的參數(shù)

  func f(a int, _ string) {}
  • ** 如果你要比較時(shí)間戳,請使用 time.Before 或 time.After ,不要使用 time.Sub 來獲得 duration (持續(xù)時(shí)間),然后檢查它的值。
  • ** 帶有上下文的函數(shù)第一個參數(shù)名為 ctx,形如:func foo(ctx Context, ...)
  • ** 幾個相同類型的參數(shù)定義可以用簡短的方式來進(jìn)行
  func f(a int, b int, s string, p string)
  func f(a, b int, s, p string)
  • ** 一個 slice 的零值是 nil

    var s []int
    fmt.Println(s, len(s), cap(s))
    if s == nil {
    fmt.Println("nil!")
    }
    // Output:
    // [] 0 0
    // nil!
  var a []string
  b := []string{}

  fmt.Println(reflect.DeepEqual(a, []string{}))
  fmt.Println(reflect.DeepEqual(b, []string{}))
  // Output:
  // false
  // true
  • ** 不要將枚舉類型與 <><= 和 >= 進(jìn)行比較

    • 使用確定的值,不要像下面這樣做:
  value := reflect.ValueOf(object)
  kind := value.Kind()
  if kind >= reflect.Chan && kind <= reflect.Slice {
    // ...
  }
  • ** 用 %+v 來打印數(shù)據(jù)的比較全的信息

  • ** 注意空結(jié)構(gòu) struct{}

  func f1() {
    var a, b struct{}
    print(&a, "\n", &b, "\n") // Prints same address
    fmt.Println(&a == &b)     // Comparison returns false
  }

  func f2() {
    var a, b struct{}
    fmt.Printf("%p\n%p\n", &a, &b) // Again, same address
    fmt.Println(&a == &b)          // ...but the comparison returns true
  }
  • **

    • 例如: errors.Wrap(err, "additional message to a given error")
  • **

    在 Go 里面要小心使用 range:

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

    從 map 讀取一個不存在的 key 將不會 panic

    • value := map["no_key"] 將得到一個 0 值
    • value, ok := map["no_key"] 更好
  • **

    不要使用原始參數(shù)進(jìn)行文件操作

    • 而不是一個八進(jìn)制參數(shù) os.MkdirAll(root, 0700)
    • 使用此類型的預(yù)定義常量 os.FileMode
  • **

    不要忘記為 iota 指定一種類型

    const (
      _ = iota
      testvar         // testvar 將是 int 類型
    )

vs

    type myType int
    const (
      _ myType = iota
      testvar         // testvar 將是 myType 類型
    )

不要在你不擁有的結(jié)構(gòu)上使用 encoding/gob

在某些時(shí)候,結(jié)構(gòu)可能會改變,而你可能會錯過這一點(diǎn)。因此,這可能會導(dǎo)致很難找到 bug。

不要依賴于計(jì)算順序,特別是在 return 語句中。

  // BAD
  return res, json.Unmarshal(b, &res)

  // GOOD
  err := json.Unmarshal(b, &res)
  return res, err

防止結(jié)構(gòu)體字段用純值方式初始化,添加 _ struct {} 字段:

type Point struct {
  X, Y float64
  _    struct{} // to prevent unkeyed literals
}

對于 Point {X:1,Y:1} 都可以,但是對于 Point {1,1} 則會出現(xiàn)編譯錯誤:

./file.go:1:11: too few values in Point literal

當(dāng)在你所有的結(jié)構(gòu)體中添加了 _ struct{} 后,使用 go vet 命令進(jìn)行檢查,(原來聲明的方式)就會提示沒有足夠的參數(shù)。

為了防止結(jié)構(gòu)比較,添加 func 類型的空字段

  type Point struct {
    _ [0]func() // unexported, zero-width non-comparable field
    X, Y float64
  }

http.HandlerFunc 比 http.Handler 更好

用 http.HandlerFunc 你僅需要一個 func,http.Handler 需要一個類型。

移動 defer 到頂部

這可以提高代碼可讀性并明確函數(shù)結(jié)束時(shí)調(diào)用了什么。

JavaScript 解析整數(shù)為浮點(diǎn)數(shù)并且你的 int64 可能溢出

用 json:"id,string" 代替

type Request struct {
  ID int64 `json:"id,string"`
}

并發(fā)

  • ** 以線程安全的方式創(chuàng)建單例(只創(chuàng)建一次)的最好選擇是 sync.Once

    • 不要用 flags, mutexes, channels or atomics
  • ** 永遠(yuǎn)不要使用 select{}, 省略通道, 等待信號

  • ** 不要關(guān)閉一個發(fā)送(寫入)管道,應(yīng)該由創(chuàng)建者關(guān)閉

    • 往一個關(guān)閉的 channel 寫數(shù)據(jù)會引起 panic
  • ** math/rand 中的 func NewSource(seed int64) Source 不是并發(fā)安全的,默認(rèn)的 lockedSource 是并發(fā)安全的。

  • ** 當(dāng)你需要一個自定義類型的 atomic 值時(shí),可以使用 atomic.Value

性能

  • ** 不要省略 defer

    • 在大多數(shù)情況下 200ns 加速可以忽略不計(jì)
  • ** 總是關(guān)閉 http body defer r.Body.Close()

    • 除非你需要泄露 goroutine
  • ** 過濾但不分配新內(nèi)存

  b := a[:0]
  for _, x := range a {
      if f(x) {
        b = append(b, x)
      }
  }

為了幫助編譯器刪除綁定檢查,請參見此模式 _ = b [7]

  • ** time.Time 有指針字段 time.Location 并且這對 go GC 不好

    • 只有使用了大量的 time.Time 才(對性能)有意義,否則用 timestamp 代替
  • ** regexp.MustCompile 比 regexp.Compile 更好

    • 在大多數(shù)情況下,你的正則表達(dá)式是不可變的,所以你最好在 func init 中初始化它
  • ** 請勿在你的熱點(diǎn)代碼中過度使用 fmt.Sprintf. 由于維護(hù)接口的緩沖池和動態(tài)調(diào)度,它是很昂貴的。

    • 如果你正在使用 fmt.Sprintf("%s%s", var1, var2), 考慮使用簡單的字符串連接。
    • 如果你正在使用 fmt.Sprintf("%x", var), 考慮使用 hex.EncodeToString or strconv.FormatInt(var, 16)
  • ** 如果你不需要用它,可以考慮丟棄它,例如io.Copy(ioutil.Discard, resp.Body)

    • HTTP 客戶端的傳輸不會重用連接,直到body被讀完和關(guān)閉。
  res, _ := client.Do(req)
  io.Copy(ioutil.Discard, res.Body)
  defer res.Body.Close()
  • ** 不要在循環(huán)中使用 defer,否則會導(dǎo)致內(nèi)存泄露

    • 因?yàn)檫@些 defer 會不斷地填滿你的棧(內(nèi)存)
  • ** 不要忘記停止 ticker, 除非你需要泄露 channel

  ticker := time.NewTicker(1 * time.Second)
  defer ticker.Stop()
  • ** 用自定義的 marshaler 去加速 marshaler 過程

    • 但是在使用它之前要進(jìn)行定制!
  func (entry Entry) MarshalJSON() ([]byte, error) {
    buffer := bytes.NewBufferString("{")
    first := true
    for key, value := range entry {
        jsonValue, err := json.Marshal(value)
        if err != nil {
            return nil, err
        }
        if !first {
            buffer.WriteString(",")
        }
        first = false
        buffer.WriteString(key + ":" + string(jsonValue))
    }
    buffer.WriteString("}")
    return buffer.Bytes(), nil
  }
  • **

    sync.Map 不是萬能的,沒有很強(qiáng)的理由就不要使用它。

  • **

    在 sync.Pool 中分配內(nèi)存存儲非指針數(shù)據(jù)

  • **

    為了隱藏逃生分析的指針,你可以小心使用這個函數(shù)::

  // noescape hides a pointer from escape analysis.  noescape is
  // the identity function but escape analysis doesn't think the
  // output depends on the input. noescape is inlined and currently
  // compiles down to zero instructions.
  //go:nosplit
  func noescape(p unsafe.Pointer) unsafe.Pointer {
    x := uintptr(p)
    return unsafe.Pointer(x ^ 0)
  }
  • **

    對于最快的原子交換,你可以使用這個 m := (*map[int]int)(atomic.LoadPointer(&ptr))

  • **

    如果執(zhí)行許多順序讀取或?qū)懭氩僮?,請使用緩沖 I/O

    • 減少系統(tǒng)調(diào)用次數(shù)
  • **

    有 2 種方法清空一個 map:

    • 重用 map 內(nèi)存 (但是也要注意 m 的回收)
  for k := range m {
    delete(m, k)
  }
  • 分配新的
  m = make(map[int]int)

構(gòu)建

  • ** 用這個命令 go build -ldflags="-s -w" ... 去掉你的二進(jìn)制文件

  • ** 拆分構(gòu)建不同版本的簡單方法

    • 用 // +build integration 并且運(yùn)行他們 go test -v --tags integration .
  • ** 最小的 Go Docker 鏡像

  • ** run go format on CI and compare diff

    • 這將確保一切都是生成的和承諾的
  • ** 用最新的 Go 運(yùn)行 Travis-CI,用 travis 1

  • ** 檢查代碼格式是否有錯誤 diff -u <(echo -n) <(gofmt -d .)

測試

  • ** 測試名稱 package_test 比 package 要好
  • ** go test -short 允許減少要運(yùn)行的測試數(shù)
  func TestSomething(t *testing.T) {
    if testing.Short() {
      t.Skip("skipping test in short mode.")
    }
  }
  • ** 根據(jù)系統(tǒng)架構(gòu)跳過測試
  if runtime.GOARM == "arm" {
    t.Skip("this doesn't work under ARM")
  }
  • ** 用 testing.AllocsPerRun 跟蹤你的內(nèi)存分配

  • ** 多次運(yùn)行你的基準(zhǔn)測試可以避免噪音。

    • go test -test.bench=. -count=20

工具

  • **

    快速替換 gofmt -w -l -r "panic(err) -> log.Error(err)" .

  • **

    go list 允許找到所有直接和傳遞的依賴關(guān)系

    • go list -f '{{ .Imports }}' package
    • go list -f '{{ .Deps }}' package
  • **

    對于快速基準(zhǔn)比較,我們有一個 benchstat 工具。

  • **

    go-critic linter 從這個文件中強(qiáng)制執(zhí)行幾條建議

  • **

    go mod why -m <module> 告訴我們?yōu)槭裁刺囟ǖ哪K在 go.mod 文件中。

  • **

    GOGC=off go build ... 應(yīng)該會加快構(gòu)建速度 source

  • **

    內(nèi)存分析器每 512KB 記錄一次分配。你能通過 GODEBUG 環(huán)境變量增加比例,來查看你的文件的更多詳細(xì)信息。

  • **

    go mod why -m <module> 告訴我們?yōu)槭裁刺囟ǖ哪K是在 go.mod 文件中。

其他

  • ** dump goroutines 
  go func() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGQUIT)
    buf := make([]byte, 1<<20)
    for {
      <-sigs
      stacklen := runtime.Stack(buf, true)
      log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n"  , buf[:stacklen])
    }
  }()
  • ** 在編譯期檢查接口的實(shí)現(xiàn)

      var _ io.Reader = (*MyFastReader)(nil)
  • ** len(nil) = 0

  • ** 匿名結(jié)構(gòu)很酷

  var hits struct {
    sync.Mutex
    n int
  }
  hits.Lock()
  hits.n++
  hits.Unlock()
  • **

    httputil.DumpRequest 是非常有用的東西,不要自己創(chuàng)建

  • **

    獲得調(diào)用堆棧,我們可以使用 runtime.Caller

  • **

    要 marshal 任意的 JSON, 你可以 marshal 為 map[string]interface{}{}

  • **

    配置你的 CDPATH 以便你能在任何目錄執(zhí)行 cd github.com/golang/go

    • 添加這一行代碼到 bashrc(或者其他類似的) export CDPATH=$CDPATH:$GOPATH/src
  • **

    從一個 slice 生成簡單的隨機(jī)元素

    • []string{"one", "two", "three"}[rand.Intn(3)]

參考資料: github.com/cristaloleg…

總結(jié)

到此這篇關(guān)于Go你不得不知道的一些實(shí)用小技巧的文章就介紹到這了,更多相關(guān)Go小技巧內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang對mongodb進(jìn)行聚合查詢詳解

    Golang對mongodb進(jìn)行聚合查詢詳解

    這篇文章主要為大家詳細(xì)介紹了Golang對mongodb進(jìn)行聚合查詢的方法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Golang有一點(diǎn)的幫助,需要的可以參考一下
    2023-02-02
  • golang類型轉(zhuǎn)換組件Cast的使用詳解

    golang類型轉(zhuǎn)換組件Cast的使用詳解

    這篇文章主要介紹了golang類型轉(zhuǎn)換組件Cast的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用golang,感興趣的朋友可以了解下
    2021-02-02
  • Go 計(jì)時(shí)器使用示例全面講解

    Go 計(jì)時(shí)器使用示例全面講解

    這篇文章主要為大家介紹了Go 計(jì)時(shí)器使用示例全面講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Go語言學(xué)習(xí)技巧之命名規(guī)范

    Go語言學(xué)習(xí)技巧之命名規(guī)范

    最近在學(xué)習(xí)go語言,發(fā)現(xiàn)了不少需要整理的知識點(diǎn),所以整理下分享出來,下面這篇文章主要給大家介紹了關(guān)于Go語言學(xué)習(xí)技巧之命名規(guī)范的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-12-12
  • 深入了解Golang中Slice切片的使用

    深入了解Golang中Slice切片的使用

    本文主要為大家詳細(xì)介紹了Golang中Slice切片的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2023-02-02
  • 使用Go語言實(shí)現(xiàn)接口繼承的方式

    使用Go語言實(shí)現(xiàn)接口繼承的方式

    在Go語言中,接口(interface)是一種定義方法集合的類型,它并不包含方法的具體實(shí)現(xiàn),只是規(guī)定實(shí)現(xiàn)該接口的類型必須提供這些方法的實(shí)現(xiàn),下面我將通過示例代碼來詳細(xì)解釋如何使用Go語言實(shí)現(xiàn)接口組合,以及為什么這種方式可以看作是實(shí)現(xiàn)接口繼承的一種方式
    2024-05-05
  • 一文帶你深入了解Golang中的Mutex

    一文帶你深入了解Golang中的Mutex

    這篇文章主要為大家詳細(xì)介紹了Golang中Mutex的相關(guān)知識,知其然,更要知其所以然。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03
  • Golang工作池的使用實(shí)例講解

    Golang工作池的使用實(shí)例講解

    我們使用Go語言開發(fā)項(xiàng)目,常常會使用到goroutine;goroutine太多會造成系統(tǒng)占用過高或其他系統(tǒng)異常,我們可以將goroutine控制指定數(shù)量,且減少goroutine的創(chuàng)建,這就運(yùn)用到Go工作池,下面就介紹和使用一下
    2023-02-02
  • 在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解

    在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解

    這篇文章主要介紹了在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解

    Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解

    這篇文章主要為大家介紹了Golang 基礎(chǔ)之函數(shù)使用(匿名遞歸閉包)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評論