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

Go語言規(guī)范context?類型的key用法示例解析

 更新時間:2023年08月17日 08:47:22   作者:amc  
這篇文章主要為大家介紹了Go語言規(guī)范context?類型的key用法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

現(xiàn)在團隊里幾乎所有的代碼都需要經(jīng)過 Code Review(代碼審查)之后,才允許合入主分支。作為 CR 負責人之一,在 CR 中看到了不少不適合的問題,也看到了不少值得學習的點。筆者決定從今天開始,一點一滴地記錄這些做法、經(jīng)驗、教訓,以饗讀者。

這系列文章,我都會先拋出一句話規(guī)范說明,然后解釋問題的背景,最后再給出正確的規(guī)范。

一句話規(guī)范

  • 當使用 context.Context 類型保存 KV 對時, key 不能使用原生類型,而應該使用派生類型

問題背景

我們知道,可以利用 context.Context 類型來存一些自定義的鍵值對——當然了,需要保存新的 context 對象:

ctx = context.WithValue(ctx, someKey, someValue)

很快就可以注意到 key 的參數(shù)類型是 any,也就是 Go 1.17 之前的 interface{}。“可能是為了能夠使用 int 吧?” ——初學者很可能會這么想。

在實際的 CR 中,可以看到很多人都使用 string 類型作為 key,比如這是一個非常典型的例子:

ctx = context.WithValue(ctx, "openid", userOpenID)

存在問題

如果你使用了 VSCode,并且一鍵安裝了 Go 開發(fā)工具包,那么 VSCode 大概率也安裝了 golangci-lint 工具。此時,上面的這段代碼會喜提一個 warning:

SA1029: should not use built-in type string as key for value; define your own type to avoid collisions (staticcheck)

告警信息雖然是英文,但很容易理解:

  • 不應該使用內(nèi)建類型作為 KV 中 key 的類型,而應該使用自定義的類型來避免沖突。

為什么要這么做呢?很簡單,現(xiàn)代軟件都是團隊開發(fā)的,多模塊相互耦合,互相協(xié)作。在一個 ctx 對象的整個生命周期中,它需要經(jīng)過多個邏輯 / 模塊的洗禮,每一個模塊都可能使用 ctx 來存儲相應信息。

假設 user 模塊,它使用 ctx 類型緩存了用戶的 openid 字段。這個邏輯沒什么問題。然后這個 ctx(和代碼邏輯)繼續(xù)往后走,大家約定,就使用這個 "openid" 來存儲。

有一天,來了一個緊急需求,比如說要做一個群聊功能,盡可能復用老代碼減少開發(fā)。或許 group 模塊就利用了 user 模塊的代碼。好巧不巧,從其他團隊過來支援的開發(fā)同學,也使用了 "openid" 這個 key,來存儲群主的 openid。結果繞了一圈,這位同學發(fā)現(xiàn):咦怎么這群主的 openid 老變成別人的 openid?擱這群主輪流做是吧?

解決方法

可能有人覺得:那我把 key 的定義統(tǒng)一收集起來規(guī)定不就行了?解決一個問題總有上中下策,這是個辦法,但是一個下下下策。軟件工程主打一個分而治之,在沒有必要的情況下,盡可能避免集中式的管理。

最上策的解決方法簡單而言,就是使用自定義的類型作為 key 的類型。我們看看下面的代碼:

type myString string
func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "openid", "不是群主")
    ctx = context.WithValue(ctx, myString("openid"), "群主")
    fmt.Println(ctx.Value("openid"))
    fmt.Println(ctx.Value(myString("openid")))
}

兩行輸出:

不是群主
群主

這就非常清晰了,盡管底層類型相同(都是 string 類型),但是經(jīng)過 type 定義之后,Go 是作為完全不同的 key 來處理的。針對具體類型自定義 key 類型之后,很好地解決了同名 key 沖突的問題。

不過呢,如果你并不需要使用同一個 key 類型,存儲多個不同 value,那么上面的模式還只能說是中策,真正的上策是這么做的:

type myString struct{}

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "openid", "不是群主")
    ctx = context.WithValue(ctx, myString{}, "群主")

    fmt.Println(ctx.Value("openid"))
    fmt.Println(ctx.Value(myString{}))
}

我還記得我當年第一次看到這個模式的時候,我就是上圖的這個表情。是的,struct{} 類型也可以作為 KV 的 key 類型——當然了,也應該定義為自定義類型。

使用 struct{} 的好處可是大大的多:首先,這個類型在 Go 中原則上是不占內(nèi)存空間和 gc 開銷的,可以提升性能;其次,這少了開發(fā)者額外 “寫一個 key” 的時間(類型往往可以通過 IDE 快速補全),大大提高了敲代碼的速度呀。

典型例子

使用 context WithValue 方法,有一個很典型的例子,就是在 ctx 中存入一個 trace ID,用于跟蹤整個調(diào)用鏈。那么,我們可以包裝一個 traceid 包,比較規(guī)范的寫法是這樣的:

// Package traceid 用于在 context 中維護 trace ID
package traceid
import "context"
// WithTraceID 往 context 中存入 trace ID
func WithTraceID(ctx context.Context, traceID string) context.Context {
    return context.WithValue(ctx, traceIDKey{}, traceID)
}
// TraceID 從 context 中提取 trace ID
func TraceID(ctx context.Context) string {
    v := context.Value(ctx, traceIDKey{})
    id, _ := v.(string)
    return id
}
type traceIDKey struct{}

以上就是Go語言規(guī)范context 類型的key用法示例解析的詳細內(nèi)容,更多關于Go context類型key的資料請關注腳本之家其它相關文章!

相關文章

  • Golang并發(fā)編程之Channel詳解

    Golang并發(fā)編程之Channel詳解

    傳統(tǒng)的并發(fā)編程模型是基于線程和共享內(nèi)存的同步訪問控制的,共享數(shù)據(jù)受鎖的保護,使用線程安全的數(shù)據(jù)結構會使得這更加容易。本文將詳細介紹Golang并發(fā)編程中的Channel,,需要的朋友可以參考下
    2023-05-05
  • Go 并發(fā)讀寫 sync.map 詳細

    Go 并發(fā)讀寫 sync.map 詳細

    閱讀本文你將會明確 sync.Map 和原生 map +互斥鎖/讀寫鎖之間的性能情況。標準庫 sync.Map 雖說支持并發(fā)讀寫 map,但更適用于讀多寫少的場景,因為他寫入的性能比較差,使用時要考慮清楚這一點。
    2021-10-10
  • 關于Golang標準庫flag的全面講解

    關于Golang標準庫flag的全面講解

    這篇文章主要介紹了關于Golang標準庫flag的全面講解,這個庫的代碼量只有1000行左右,卻提供了非常完善的命令行參數(shù)解析功能,更多相關內(nèi)容需要的朋友可以參考一下
    2022-09-09
  • Golang?Mutex?原理詳細解析

    Golang?Mutex?原理詳細解析

    這篇文章主要介紹了Golang?Mutex原理詳細解析,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • Go語言題解LeetCode268丟失的數(shù)字示例詳解

    Go語言題解LeetCode268丟失的數(shù)字示例詳解

    這篇文章主要為大家介紹了Go語言題解LeetCode268丟失的數(shù)字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 詳解Golang中使用map時的注意問題

    詳解Golang中使用map時的注意問題

    Golang中的map是一種數(shù)據(jù)結構,它允許你使用鍵值對的形式存儲和訪問數(shù)據(jù),map在Go中是非排序的,提供了高效查找、插入和刪除元素的能力,特別是當鍵是不可變類型,本文給大家詳細介紹了Golang中使用map時的注意問題,需要的朋友可以參考下
    2024-06-06
  • jenkins配置golang?代碼工程自動發(fā)布的實現(xiàn)方法

    jenkins配置golang?代碼工程自動發(fā)布的實現(xiàn)方法

    這篇文章主要介紹了jenkins配置golang?代碼工程自動發(fā)布,jks是個很好的工具,使用方法也很多,我只用了它簡單的功能,對jenkins配置golang相關知識感興趣的朋友一起看看吧
    2022-07-07
  • Prometheus Go client library使用方式詳解

    Prometheus Go client library使用方式詳解

    這篇文章主要為大家介紹了Prometheus Go client library使用方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Golang實現(xiàn)單元測試中的接口層

    Golang實現(xiàn)單元測試中的接口層

    接口層主要負責的就是請求的處理,最常見的就是?HTTP?請求的處理。這篇文章主要為大家介紹了Golang如何實現(xiàn)單元測試中的接口層,需要的可以參考一下
    2023-03-03
  • 詳解Go中gin框架如何實現(xiàn)帶顏色日志

    詳解Go中gin框架如何實現(xiàn)帶顏色日志

    當我們在終端上(比如Goland)運行gin框架搭建的服務時,會發(fā)現(xiàn)輸出的日志是可以帶顏色的,那這是如何實現(xiàn)的呢?本文就來和大家簡單講講
    2023-04-04

最新評論