最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

10個可以優(yōu)化代碼的Go語言技巧分享

 更新時間:2024年01月15日 15:55:32   作者:愛發(fā)白日夢的后端  
這篇文章主要為大家詳細介紹了10個可以優(yōu)化代碼的Go語言技巧,從而讓我們的代碼更加優(yōu)雅,文中的示例代碼講解詳細,需要的小伙伴可以參考下

在開發(fā)生產(chǎn)項目的過程中,我注意到經(jīng)常會發(fā)現(xiàn)自己在重復編寫代碼,使用某些技巧時沒有意識到,直到后來回顧工作時才意識到。

為了解決這個問題,我開發(fā)了一種解決方案,對我來說非常有幫助,我覺得對其他人也可能有用。

以下是一些從我的實用程序庫中隨機挑選的有用且多功能的代碼片段,沒有特定的分類或特定于系統(tǒng)的技巧。

1. 追蹤執(zhí)行時間的技巧

如果你想追蹤 Go 中函數(shù)的執(zhí)行時間,有一個簡單高效的技巧可以用一行代碼實現(xiàn),使用 defer 關(guān)鍵字即可。你只需要一個 TrackTime 函數(shù):

// Utility
func TrackTime(pre time.Time) time.Duration {
  elapsed := time.Since(pre)
  fmt.Println("elapsed:", elapsed)

  return elapsed
}

func TestTrackTime(t *testing.T) {
  defer TrackTime(time.Now()) // <--- THIS

  time.Sleep(500 * time.Millisecond)
}

// 輸出:
// elapsed: 501.11125ms

兩階段延遲執(zhí)行

Go 的 defer 不僅僅是用于清理任務,還可以用于準備任務,考慮以下示例:

func setupTeardown() func() {
    fmt.Println("Run initialization")
    return func() {
        fmt.Println("Run cleanup")
    }
}

func main() {
    defer setupTeardown()() // <--------
    fmt.Println("Main function called")
}

// 輸出:
// Run initialization
// Main function called
// Run cleanup

這種模式的美妙之處在于,只需一行代碼,你就可以完成諸如以下任務:

  • 打開數(shù)據(jù)庫連接,然后關(guān)閉它。
  • 設置模擬環(huán)境,然后拆除它。
  • 獲取分布式鎖,然后釋放它。
  • ...

"嗯,這似乎很聰明,但它在現(xiàn)實中有什么用處呢?"

還記得追蹤執(zhí)行時間的技巧嗎?我們也可以這樣做:

func TrackTime() func() {
  pre := time.Now()
  return func() {
    elapsed := time.Since(pre)
    fmt.Println("elapsed:", elapsed)
  }
}

func main() {
  defer TrackTime()()

  time.Sleep(500 * time.Millisecond)
}

注意!如果我連接到數(shù)據(jù)庫時出現(xiàn)錯誤怎么辦?

確實,像 defer TrackTime() 或 defer ConnectDB() 這樣的模式不會妥善處理錯誤。這種技巧最適合用于測試或者當你愿意冒著致命錯誤的風險時使用,參考下面這種面向測試的方法:

func TestSomething(t *testing.T) {
  defer handleDBConnection(t)()
  // ...
}

func handleDBConnection(t *testing.T) func() {
  conn, err := connectDB()
  if err != nil {
    t.Fatal(err)
  }

  return func() {
    fmt.Println("Closing connection", conn)
  }
}

這樣,在測試期間可以處理數(shù)據(jù)庫連接的錯誤。

2. 預分配切片

根據(jù)文章《Go 性能提升技巧》中的見解,預分配切片或映射可以顯著提高 Go 程序的性能。

但是值得注意的是,如果我們不小心使用 append 而不是索引(如 a[i]),這種方法有時可能導致錯誤。你知道嗎,我們可以在不指定數(shù)組長度(為零)的情況下使用預分配的切片,就像在上述文章中解釋的那樣?這使我們可以像使用 append 一樣使用預分配的切片:

// 與其
a := make([]int, 10)
a[0] = 1

// 不如這樣使用
b := make([]int, 0, 10)
b = append(b, 1)

3. 鏈式調(diào)用

鏈式調(diào)用技術(shù)可以應用于函數(shù)(指針)接收器。為了說明這一點,讓我們考慮一個 Person 結(jié)構(gòu),它有兩個函數(shù) AddAge 和 Rename,用于對其進行修改。

type Person struct {
  Name string
  Age  int
}

func (p *Person) AddAge() {
  p.Age++
}

func (p *Person) Rename(name string) {
  p.Name = name
}

如果你想給一個人增加年齡然后給他們改名字,常規(guī)的方法是:

func main() {
  p := Person{Name: "Aiden", Age: 30}

  p.AddAge()
  p.Rename("Aiden 2")
}

或者,我們可以修改 AddAge 和 Rename 函數(shù)接收器,使其返回修改后的對象本身,即使它們通常不返回任何內(nèi)容。

func (p *Person) AddAge() *Person {
  p.Age++
  return p
}

func (p *Person) Rename(name string) *Person {
  p.Name = name
  return p
}

通過返回修改后的對象本身,我們可以輕松地將多個函數(shù)接收器鏈在一起,而無需添加不必要的代碼行:

p = p.AddAge().Rename("Aiden 2")

4. Go 1.20 允許將切片解析為數(shù)組或數(shù)組指針

當我們需要將切片轉(zhuǎn)換為固定大小的數(shù)組時,不能直接賦值,例如:

a := []int{0, 1, 2, 3, 4, 5}
var b [3]int = a[0:3]

// 在變量聲明中不能將 a[0:3](類型為 []int 的值)賦值給 [3]int 類型的變量
// (不兼容的賦值)

為了將切片轉(zhuǎn)換為數(shù)組,Go 團隊在 Go 1.17 中更新了這個特性。隨著 Go 1.20 的發(fā)布,借助更方便的字面量,轉(zhuǎn)換過程變得更加簡單:

// Go 1.20
func Test(t *testing.T) {
   a := []int{0, 1, 2, 3, 4, 5}
   b := [3]int(a[0:3])

  fmt.Println(b) // [0 1 2]
}

// Go 1.17
func TestM2e(t *testing.T) {
  a := []int{0, 1, 2, 3, 4, 5}
  b := *(*[3]int)(a[0:3])

  fmt.Println(b) // [0 1 2]
}

只是一個快速提醒:你可以使用 a[:3] 替代 a[0:3]。我提到這一點是為了更清晰地說明。

5. 使用 "import _" 進行包初始化

有時,在庫中,你可能會遇到結(jié)合下劃線 (_) 的導入語句,如下所示:

import (
  _ "google.golang.org/genproto/googleapis/api/annotations"
)

這將執(zhí)行包的初始化代碼(init 函數(shù)),而無需為其創(chuàng)建名稱引用。這允許你在運行代碼之前初始化包、注冊連接和執(zhí)行其他任務。

讓我們通過一個示例來更好地理解它的工作原理:

// 下劃線
package underscore

func init() {
  fmt.Println("init called from underscore package")
}
// main
package main

import (
  _ "lab/underscore"
)

func main() {}
// 輸出:init called from underscore package

6. 使用 "import ." 進行導入

在了解了如何使用下劃線進行導入后,讓我們看看如何更常見地使用點 (.) 運算符。

作為開發(fā)者,點 (.) 運算符可用于在不必指定包名的情況下使用導入包的導出標識符,這對于懶惰的開發(fā)者來說是一個有用的快捷方式。

很酷,對吧?這在處理項目中的長包名時特別有用,比如 externalmodel 或 doingsomethinglonglib。

為了演示,這里有一個簡單的例子:

package main

import (
  "fmt"
  . "math"
)

func main() {
  fmt.Println(Pi) // 3.141592653589793
  fmt.Println(Sin(Pi / 2)) // 1
}

7. Go 1.20 允許將多個錯誤合并為單個錯誤

Go 1.20 引入了對錯誤包的新功能,包括對多個錯誤的支持以及對 errors.Is 和 errors.As 的更改。

在 errors 中添加的一個新函數(shù)是 Join,我們將在下面詳細討論它:

var (
  err1 = errors.New("Error 1st")
  err2 = errors.New("Error 2nd")
)

func main() {
  err := err1
  err = errors.Join(err, err2)

  fmt.Println(errors.Is(err, err1)) // true
  fmt.Println(errors.Is(err, err2)) // true
}

如果有多個任務導致錯誤,你可以使用 Join 函數(shù)而不是手動管理數(shù)組。這簡化了錯誤處理過程。

8. 檢查接口是否為真正的 nil

即使接口持有的值為 nil,也不意味著接口本身為 nil。這可能導致 Go 程序中的意外錯誤。因此,重要的是要知道如何檢查接口是否為真正的 nil。

func main() {
  var x interface{}
  var y *int = nil
  x = y

  if x != nil {
    fmt.Println("x != nil") // <-- 實際輸出
  } else {
    fmt.Println("x == nil")
  }

  fmt.Println(x)
}

// 輸出:
// x != nil
// <nil>

我們?nèi)绾未_定 interface{} 值是否為 nil 呢?幸運的是,有一個簡單的工具可以幫助我們實現(xiàn)這一點:

func IsNil(x interface{}) bool {
  if x == nil {
    return true
  }

  return reflect.ValueOf(x).IsNil()
}

9. 在 JSON 中解析 time.Duration

當解析 JSON 時,使用 time.Duration 可能是一個繁瑣的過程,因為它需要在一秒的后面添加 9 個零(即 1000000000)。為了簡化這個過程,我創(chuàng)建了一個名為 Duration 的新類型:

type Duration time.Duration

為了將字符串(如 "1s" 或 "20h5m")解析為 int64 類型的持續(xù)時間,我還為這個新類型實現(xiàn)了自定義的解析邏輯:

func (d *Duration) UnmarshalJSON(b []byte) error {
  var s string
  if err := json.Unmarshal(b, &s); err != nil {
    return err
  }
  dur, err := time.ParseDuration(s)
  if err != nil {
    return err
  }
  *d = Duration(dur)
  return nil
}

但是,需要注意的是,變量 'd' 不應為 nil,否則可能會導致編組錯誤?;蛘?,你還可以在函數(shù)開頭對 'd' 進行檢查。

10. 避免裸參數(shù)

當處理具有多個參數(shù)的函數(shù)時,僅通過閱讀其用法來理解每個參數(shù)的含義可能會令人困惑??紤]以下示例:

printInfo("foo", true, true)

如果不檢查 printInfo 函數(shù),那么第一個 'true' 和第二個 'true' 的含義是什么呢?當你有一個具有多個參數(shù)的函數(shù)時,僅通過閱讀其用法來理解參數(shù)的含義可能會令人困惑。

但是,我們可以使用注釋使代碼更易讀。例如:

// func printInfo(name string, isLocal, done bool)

printInfo("foo", true /* isLocal */, true /* done */)

有些 IDE 也支持這個功能,可以在函數(shù)調(diào)用建議中顯示注釋,但可能需要在設置中啟用。

到此這篇關(guān)于10個可以優(yōu)化代碼的Go語言技巧分享的文章就介紹到這了,更多相關(guān)Go技巧內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言入門之函數(shù)的定義與使用

    Go語言入門之函數(shù)的定義與使用

    函數(shù)是一段代碼的片段,包含連續(xù)的執(zhí)行語句,它可以將零個或多個輸入?yún)?shù)映射到零個或多個參數(shù)輸出。本文將通過示例和大家詳細聊聊Go語言中函數(shù)的定義與使用,感興趣的可以了解一下
    2022-11-11
  • golang如何實現(xiàn)mapreduce單進程版本詳解

    golang如何實現(xiàn)mapreduce單進程版本詳解

    這篇文章主要給大家介紹了關(guān)于golang如何實現(xiàn)mapreduce單進程版本的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-01-01
  • Go語言題解LeetCode463島嶼的周長示例詳解

    Go語言題解LeetCode463島嶼的周長示例詳解

    這篇文章主要為大家介紹了Go語言題解LeetCode463島嶼的周長示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Go語言學習之接口類型(interface)詳解

    Go語言學習之接口類型(interface)詳解

    接口是用來定義行為的類型,定義的行為不由接口直接實現(xiàn),而由通過方法由定義的類型實現(xiàn),本文就來和大家詳細講講Go語言中接口的使用吧
    2023-03-03
  • Go語言實現(xiàn)熱更新具體步驟

    Go語言實現(xiàn)熱更新具體步驟

    這篇文章主要為大家介紹了Go語言實現(xiàn)熱更新具體步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Go語言WaitGroup使用時需要注意的坑

    Go語言WaitGroup使用時需要注意的坑

    Go語言中WaitGroup的用途是它能夠一直等到所有的goroutine執(zhí)行完成,并且阻塞主線程的執(zhí)行,直到所有的goroutine執(zhí)行完成。之前一直使用也沒有問題,但最近通過同事的一段代碼引起了關(guān)于WaitGroup的注意,下面這篇文章就介紹了WaitGroup使用時需要注意的坑及填坑。
    2016-12-12
  • Golang實現(xiàn)HTTP編程請求和響應

    Golang實現(xiàn)HTTP編程請求和響應

    本文主要介紹了Golang實現(xiàn)HTTP編程請求和響應,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • Go語言基礎(chǔ)結(jié)構(gòu)體用法及示例詳解

    Go語言基礎(chǔ)結(jié)構(gòu)體用法及示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)結(jié)構(gòu)體的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-11-11
  • Go與Rust高性能解析JSON實現(xiàn)方法示例

    Go與Rust高性能解析JSON實現(xiàn)方法示例

    這篇文章主要為大家介紹了Go與Rust高性能的解析JSON實現(xiàn)方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • go帶緩沖chan實現(xiàn)消息隊列功能

    go帶緩沖chan實現(xiàn)消息隊列功能

    本文主要介紹了go帶緩沖chan實現(xiàn)消息隊列功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02

最新評論

定西市| 潼南县| 会泽县| 吉林省| 从江县| 铅山县| 潜江市| 子洲县| 堆龙德庆县| 巴彦县| 镇宁| 江西省| 南澳县| 宁波市| 长治市| 收藏| 滦平县| 定日县| 梁平县| 普兰店市| 自贡市| 富源县| 陆河县| 哈巴河县| 米易县| 铁岭县| 丰城市| 迁西县| 安溪县| 沈丘县| 香格里拉县| 太康县| 弥渡县| 台北县| 循化| 德州市| 昆山市| 灌云县| 林甸县| 通道| 永济市|