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

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

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

引言

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

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

一句話規(guī)范

  • 當(dāng)使用 context.Context 類型保存 KV 對(duì)時(shí), key 不能使用原生類型,而應(yīng)該使用派生類型

問(wèn)題背景

我們知道,可以利用 context.Context 類型來(lái)存一些自定義的鍵值對(duì)——當(dāng)然了,需要保存新的 context 對(duì)象:

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

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

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

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

存在問(wèn)題

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

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

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

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

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

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

有一天,來(lái)了一個(gè)緊急需求,比如說(shuō)要做一個(gè)群聊功能,盡可能復(fù)用老代碼減少開發(fā)?;蛟S group 模塊就利用了 user 模塊的代碼。好巧不巧,從其他團(tuán)隊(duì)過(guò)來(lái)支援的開發(fā)同學(xué),也使用了 "openid" 這個(gè) key,來(lái)存儲(chǔ)群主的 openid。結(jié)果繞了一圈,這位同學(xué)發(fā)現(xiàn):咦怎么這群主的 openid 老變成別人的 openid?擱這群主輪流做是吧?

解決方法

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

最上策的解決方法簡(jiǎn)單而言,就是使用自定義的類型作為 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)過(guò) type 定義之后,Go 是作為完全不同的 key 來(lái)處理的。針對(duì)具體類型自定義 key 類型之后,很好地解決了同名 key 沖突的問(wèn)題。

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

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{}))
}

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

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

典型例子

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

// Package traceid 用于在 context 中維護(hù) 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語(yǔ)言規(guī)范context 類型的key用法示例解析的詳細(xì)內(nèi)容,更多關(guān)于Go context類型key的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言MessageBox用法實(shí)例

    Go語(yǔ)言MessageBox用法實(shí)例

    這篇文章主要介紹了Go語(yǔ)言MessageBox用法,實(shí)例分析了MessageBox提示框的實(shí)現(xiàn)與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解

    Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解

    ttl(time-to-live) 數(shù)據(jù)存活時(shí)間,我們這里指數(shù)據(jù)在內(nèi)存中保存一段時(shí)間,超過(guò)期限則不能被讀取到,與Redis的ttl機(jī)制類似。本文僅實(shí)現(xiàn)ttl部分,不考慮序列化和反序列化
    2023-03-03
  • 基于Golang設(shè)計(jì)一套可控的定時(shí)任務(wù)系統(tǒng)

    基于Golang設(shè)計(jì)一套可控的定時(shí)任務(wù)系統(tǒng)

    這篇文章主要為大家學(xué)習(xí)介紹了如何基于Golang設(shè)計(jì)一套可控的定時(shí)任務(wù)系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-07-07
  • Go依賴注入DI工具wire使用詳解(golang常用庫(kù)包)

    Go依賴注入DI工具wire使用詳解(golang常用庫(kù)包)

    依賴注入是指程序運(yùn)行過(guò)程中,如果需要調(diào)用另一個(gè)對(duì)象協(xié)助時(shí),無(wú)須在代碼中創(chuàng)建被調(diào)用者,而是依賴于外部的注入,本文結(jié)合示例代碼給大家介紹Go依賴注入DI工具wire使用,感興趣的朋友一起看看吧
    2022-04-04
  • go get 和 go install 對(duì)比介紹

    go get 和 go install 對(duì)比介紹

    go install和go get都是Go語(yǔ)言的工具命令,但它們之間有一些區(qū)別。go get:用于從遠(yuǎn)程代碼存儲(chǔ)庫(kù)(如 GitHub)中下載或更新Go代碼包。go install:用于編譯并安裝 Go 代碼包,本文go get和go install對(duì)比介紹的非常詳細(xì),需要的朋友可以參考一下
    2023-04-04
  • go語(yǔ)言實(shí)現(xiàn)依賴注入的示例代碼

    go語(yǔ)言實(shí)現(xiàn)依賴注入的示例代碼

    依賴注入和控制反轉(zhuǎn)恰恰相反,它是一種具體的編碼技巧,我們不通過(guò) new 的方式在類內(nèi)部創(chuàng)建依賴類的對(duì)象,而是將依賴的類對(duì)象在外部創(chuàng)建好之后,通過(guò)構(gòu)造函數(shù)、函數(shù)參數(shù)等方式傳遞給類來(lái)使用,本文將給大家介紹go語(yǔ)言實(shí)現(xiàn)依賴注入,需要的朋友可以參考下
    2024-01-01
  • Go標(biāo)準(zhǔn)庫(kù)net/http包的實(shí)現(xiàn)

    Go標(biāo)準(zhǔn)庫(kù)net/http包的實(shí)現(xiàn)

    net/http是Go官方自帶的 HTTP 框架,不用裝任何第三方庫(kù),本文就來(lái)詳細(xì)的介紹一下Go標(biāo)準(zhǔn)庫(kù)net/http包的實(shí)現(xiàn),感興趣的可以了解一下
    2026-03-03
  • Go語(yǔ)言開發(fā)中有了net/http為什么還要有g(shù)in的原理及使用場(chǎng)景解析

    Go語(yǔ)言開發(fā)中有了net/http為什么還要有g(shù)in的原理及使用場(chǎng)景解析

    這篇文章主要為大家介紹了Go語(yǔ)言有了net/http標(biāo)準(zhǔn)庫(kù)為什么還要有g(shù)in第三方庫(kù)的原理及使用場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • sublime3+Golang+代碼補(bǔ)全的實(shí)現(xiàn)

    sublime3+Golang+代碼補(bǔ)全的實(shí)現(xiàn)

    本文主要介紹了sublime3+Golang+代碼補(bǔ)全的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • golang方法中receiver為指針與不為指針的區(qū)別詳析

    golang方法中receiver為指針與不為指針的區(qū)別詳析

    這篇文章主要給大家介紹了關(guān)于golang方法中receiver為指針與不為指針區(qū)別的相關(guān)資料,其實(shí)最大的區(qū)別應(yīng)該是指針傳遞的是對(duì)像的引用,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-10-10

最新評(píng)論

卫辉市| 鲜城| 乐山市| 鞍山市| 赤城县| 连山| 北辰区| 娄烦县| 荃湾区| 开阳县| 柘城县| 漠河县| 镇坪县| 柳河县| 古浪县| 罗江县| 姜堰市| 忻州市| 灌阳县| 松阳县| 徐水县| 郸城县| 青冈县| 镇原县| 威信县| 大洼县| 垫江县| 深水埗区| 蒙山县| 兰坪| 阿鲁科尔沁旗| 普陀区| 兰州市| 三都| 满洲里市| 天等县| 定结县| 九江县| 秦安县| 体育| 额济纳旗|