成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go1.18 泛型的好、壞亦或丑?

開發(fā) 后端
Go 泛型定了,有哪些好的使用場(chǎng)景,哪些不好的應(yīng)用場(chǎng)景,亦或哪些使用看起來丑?本文聊聊這個(gè)問題。

[[442529]]

大家好,我是程序員幽鬼。

Go 泛型定了,有哪些好的使用場(chǎng)景,哪些不好的應(yīng)用場(chǎng)景,亦或哪些使用看起來丑?本文聊聊這個(gè)問題。

1 簡(jiǎn)介

泛型很棒,而且 Go 變得比以前更方便了。但是與可能非常有用的 channel 類似,我們不應(yīng)該僅僅因?yàn)樗鼈兇嬖诰偷教幨褂盟鼈儭?/p>

除了用于數(shù)據(jù)結(jié)構(gòu),泛型還有其他很好的應(yīng)用場(chǎng)景。當(dāng)然,也有一些不好的用例,比如泛型日志器。還有一些可以使用的解決方案,但相當(dāng)丑陋,還有一些東西真的很丑。

讓我們分別看一個(gè)例子!

2 好的應(yīng)用場(chǎng)景

我真正夢(mèng)想在 Go 中做的以及我認(rèn)為我現(xiàn)在終于可以做的是 CRUD 端點(diǎn)的泛型提供程序:

  1. type Model interface { 
  2.     ID() string 
  3.  
  4. type DataProvider[MODEL Model] interface { 
  5.     FindByID(id string) (MODEL, error) 
  6.     List() ([]MODEL, error) 
  7.     Update(id string, model MODEL) error 
  8.     Insert(model MODEL) error 
  9.     Delete(id string) error 

這是一個(gè)大接口,你可以根據(jù)具體用例的需要縮短它,但是,為了完整性起見,我們暫時(shí)就這么寫。

現(xiàn)在你可以定義一個(gè)使用 DataProvider 的 HTTP 處理程序:

  1. type HTTPHandler[MODEL Model] struct { 
  2.     dataProvider DataProvider[MODEL] 
  3.  
  4. func (h HTTPHandler[MODEL]) FindByID(rw http.ResponseWriter, req *http.Request) { 
  5.     // validate request here 
  6.     id = // extract id here 
  7.     model, err := h.dataProvider.FindByID(id) 
  8.     if err != nil { 
  9.         // error handling here 
  10.         return 
  11.     } 
  12.     err = json.NewEncoder(rw).Encode(model) 
  13.     if err != nil { 
  14.         // error handling here 
  15.         return 
  16.     } 

如你所見,我們可以為每個(gè)方法實(shí)現(xiàn)一次,然后我們就完成了。我們甚至可以在事物的另一端創(chuàng)建一個(gè)客戶端,我們只需要為基本方法實(shí)現(xiàn)一次。

為什么我們?cè)谶@里使用泛型而不是簡(jiǎn)單的我們已經(jīng)定義的 Model 接口?

與在此處使用 Model 類型本身相比,泛型有一些優(yōu)點(diǎn):

  • 使用泛型方法,DataProvider 根本不需要知道 Model,也不需要實(shí)現(xiàn)它。它可以簡(jiǎn)單地提供非常強(qiáng)大的具體類型(但仍然可以為簡(jiǎn)單的用例抽象)
  • 我們可以擴(kuò)展這個(gè)解決方案并使用具體類型進(jìn)行操作。讓我們看看插入或更新的驗(yàn)證器會(huì)是什么樣子。
  1. type HTTPHandler[MODEL any] struct { 
  2.     dataProvider DataProvider[MODEL] 
  3.     InsertValidator func(new MODEL) error 
  4.     UpdateValidator func(old MODEL, new MODEL) error 

在這個(gè)驗(yàn)證器中是泛型方法的真正優(yōu)勢(shì)所在。我們將解析 HTTP 請(qǐng)求,如果定義了自定義的 InsertValidator,那么我們可以使用它來驗(yàn)證模型是否檢出,我們可以以類型安全的方式進(jìn)行并使用具體模型:

  1. type User struct { 
  2.     FirstName string 
  3.     LastName string 
  4.  
  5. func InsertValidator(u User) error { 
  6.     if u.FirstName == "" { ... }  
  7.     if u.LastName == "" { ... } 

所以我們有一個(gè)泛型的處理器,我們可以用自定義回調(diào)來調(diào)整它,它直接為我們獲取有效負(fù)載。沒有類型轉(zhuǎn)換。沒有 map。只有結(jié)構(gòu)體本身!

3 不好的應(yīng)用場(chǎng)景

一起看一個(gè)泛型日志器的例子:

  1. type GenericLogger[T any] interface { 
  2.     WithField(string, string) T 
  3.     Info(string) 

這本身還不是很有用。有更簡(jiǎn)單的方法可以將鍵值字符串對(duì)添加到日志器,并且沒有日志器(據(jù)我所知)實(shí)際實(shí)現(xiàn)此接口。我們也不需要新的日志標(biāo)準(zhǔn)。如果我們想使用 logrus[1],我們必須這樣做:

  1. type GenericLogger[T any, FIELD map[string]interface{}] interface{ 
  2.     WithFields(M) T 
  3.     Info(string) 

如果我們添加自引用部分,這實(shí)際上可能由 logrus 日志器實(shí)現(xiàn)。但是,讓我們考慮在實(shí)際結(jié)構(gòu)體中使用它,例如某種處理程序:

  1. type MessageHandler[T GenericLogger[T], FIELD map[string]interface{}] struct { 
  2.     logger GenericLogger[T, FIELD] 

為了在結(jié)構(gòu)體中使用這個(gè)日志器,我們需要使我們的結(jié)構(gòu)體泛型,這僅適用于日志器。如果 MessageHandler 本身正在處理泛型消息,那將變成第三個(gè)類型參數(shù)!

到目前為止,甚至沒有辦法將其分配給具有泛型的變量。所以,盡管我們可以用一個(gè)接口來表示這個(gè)日志器很棒,但我實(shí)際上建議不要這樣做。而我最喜歡的日志庫(kù) (zap[2]),由于其字段的性質(zhì),甚至無法用它來表示。

4 丑的場(chǎng)景

當(dāng)我使用泛型時(shí),我發(fā)現(xiàn)缺少對(duì)在方法中引入新泛型參數(shù)的支持。雖然這可能有很好的理由,但它確實(shí)需要一些解決方法。讓我們想象一下我們想要將一個(gè) map 簡(jiǎn)化為一個(gè)整數(shù)。理想情況下,我們將通過使用返回新泛型參數(shù)的方法來完成此操作,然后我們可以簡(jiǎn)單地提供 map reduce 函數(shù)。

那么,當(dāng)我們?nèi)匀幌胍苑盒头绞娇s小該 map 時(shí),我們?cè)撛趺崔k?既然沒有方法,那么讓我們創(chuàng)建一個(gè)方法:

  1. type GenericMap[KEY comparable, VALUE any] map[KEY]VALUEfunc (g GenericMap[KEY, VALUE]) Values() []VALUE { 
  2.     values := make([]VALUE, len(g)) 
  3.     for _, v := range g { 
  4.         values = append(values, v) 
  5.     } 
  6.     return values 
  7.  
  8. func Reduce[KEY comparable, VALUE anyRETURN any](g GenericMap[KEY, VALUE], callback func(RETURNKEY, VALUE "KEY comparable, VALUE any, RETURN any"RETURNRETURN { 
  9.     var r RETURN 
  10.     for k, v := range g { 
  11.         r = callback(r, k, v) 
  12.     } 
  13.     return r 

GenericMap 成為第一個(gè)參數(shù)或我們的 Reduce 函數(shù)。在這種情況下,你可以使用任何類型的 map 作為第一個(gè)參數(shù),而不是 GenericMap。然而,我想說明的一點(diǎn)是,如果這個(gè)方法本身是 GenericMap 的一部分,那就太好了。即使不是,我們?nèi)匀豢梢阅7逻@種行為。總的來說,我可能仍會(huì)在某些用例中使用這種模式,即使它實(shí)際上很丑陋。

5 真的很丑

有時(shí)你可能想要使用工廠模式,它為你提供諸如 DataProviders 之類的東西。你可能希望在動(dòng)態(tài)注冊(cè)的端點(diǎn)上獲取提供程序。所以你可以這樣做:

  1. type DataProviderFactory struct { 
  2.     dataProviders map[providerKey]any 
  3. func ProviderByName[MODEL Model](factory *DataProviderFactory, name string "MODEL Model") (DataProvider[MODEL], bool) { 
  4.         var m MODEL 
  5.     prov, has := factory.dataProviders[providerKey{namename, typ: reflect.TypeOf(m)}] 
  6.     if !has { 
  7.        return nil, false 
  8.     } 
  9.     return prov.(DataProvider[MODEL]), true  
  1. func RegisterProvider[MODEL Model](factory *DataProviderFactory, name string, p DataProvider[MODEL] "MODEL Model") { 
  2.     var m MODEL 
  3.     factory.dataProviders[providerKey{namename, typ: reflect.TypeOf(m)}] = p  

雖然這有效,雖然它可能有用,但它是很丑。它將丑陋(反射)與更丑陋(泛型)的東西結(jié)合在一起。

雖然從技術(shù)上講這應(yīng)該是類型安全的,但由于我們的復(fù)合鍵具有名稱和反射類型,它仍然很難看。我是否要把它放在生產(chǎn)代碼的任何地方,我會(huì)很糾結(jié)。

6 總結(jié)

雖然我喜歡泛型,但我認(rèn)為很難取得平衡,尤其是在開始的時(shí)候。所以我們需要確保記住它們?yōu)槭裁创嬖冢谑裁辞闆r下我們應(yīng)該使用它們,什么時(shí)候我們應(yīng)該避免它們!

原文鏈接:https://itnext.io/golang-1-18-generics-the-good-the-bad-the-ugly-5e9fa2520e76

參考資料

[1]logrus: https://github.com/sirupsen/logrus

[2]zap: https://github.com/uber-go/zap

本文轉(zhuǎn)載自微信公眾號(hào)「幽鬼」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系幽鬼公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 幽鬼
相關(guān)推薦

2021-12-15 12:59:56

Go泛型版Beta1

2021-12-02 18:21:49

GoIP 包設(shè)計(jì)

2021-12-15 10:23:56

Go 1.18 Bet語(yǔ)言泛型

2022-01-26 09:02:57

GoCut方法

2021-11-01 12:41:39

Go

2021-10-18 10:53:26

Go 代碼技術(shù)

2022-02-11 21:01:18

GoNetip網(wǎng)絡(luò)庫(kù)

2021-12-03 18:29:31

GoAny 泛型

2022-02-14 09:32:49

Go場(chǎng)景TryLock

2022-07-12 06:17:43

GoogleGolang開發(fā)工作

2022-03-18 18:00:00

編程語(yǔ)言泛型支持模糊測(cè)試

2022-01-19 08:51:00

Module工作區(qū)Go

2021-10-29 10:55:07

Go 泛型語(yǔ)言

2022-01-10 11:33:17

Go測(cè)試軟件

2023-01-28 08:05:32

轉(zhuǎn)換Go泛型

2022-01-05 07:07:37

Go核心設(shè)計(jì)

2021-12-27 18:27:18

GoTryLockJava

2022-03-28 13:34:26

Go泛型部署泛型

2020-11-24 13:05:35

Go語(yǔ)言泛型

2022-10-24 08:55:13

Go工具鏈開發(fā)者
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 一区二区三区四区在线 | 久久久久国产精品 | 国产黄色在线观看 | 91在线看 | 三级在线视频 | 视频一二区 | 国产精品久久久久久久久污网站 | 精品乱码一区二区三四区视频 | 久久久久久久久精 | 午夜在线精品 | 中文字幕 在线观看 | 国产三区视频在线观看 | 免费激情 | 国产精品3区 | 综合二区 | 久久精品国产清自在天天线 | 懂色av一区二区三区在线播放 | 亚洲国产高清免费 | 天天射夜夜操 | 欧美日韩中文国产一区发布 | 黄色片免费看视频 | 日韩不卡一区二区三区 | 久久伊人精品 | 天天操天天干天天曰 | jav成人av免费播放 | 久久精彩| 九九热在线免费视频 | 欧美日产国产成人免费图片 | 欧美日韩中 | 五月天婷婷综合 | 日韩激情在线 | 亚洲欧洲精品一区 | 国产大学生情侣呻吟视频 | 欧美黄色网络 | 精品久久久久久亚洲国产800 | 欧美日韩一区二区三区在线观看 | 国产精品久久久久久 | 亚洲午夜av久久乱码 | 久久不卡日韩美女 | 91精品国产欧美一区二区成人 | 国产精品久久久久一区二区三区 |