Go 1.18 中基于泛型的自引用接口
我非常喜歡結(jié)構(gòu)類型(structural typing,也稱為鴨子類型,但有一些細(xì)微的技術(shù)差異)。但有些事情我想做而一直無法做,直到泛型出現(xiàn)。
目前 Go1.18 Beta1 發(fā)布,終于可以實(shí)現(xiàn)我的想法了。它按預(yù)期工作,而且速度很快!即使在單個(gè)項(xiàng)目中,它也可以使我免于進(jìn)行大量復(fù)制。(可以在此處找到我對(duì)泛型讀取-復(fù)制-更新 map 的嘗試:https://github.com/mier85/rcu)
01 問題
讓我們先看看沒有泛型時(shí)一直困擾我的問題。假設(shè)有如下 interface:
type?Logger?interface?{
????WithField(name,?value?string)?Logger
????Info(message?string)
}
這是一個(gè)非常簡(jiǎn)單的記錄器(Logger),你可以向其中添加字段并返回自身。我們似乎不需要泛型。但是沒有泛型,我們?cè)诰唧w實(shí)現(xiàn)中必須使用 Logger,這打破了隱式接口:https://go.dev/tour/methods/10,即實(shí)現(xiàn)中耦合了接口。
因此,我們需要從 WithField 返回 Logger 以實(shí)現(xiàn)接口,它將我們的包與定義該接口的包緊密耦合在一起了:
type?MyLogger?struct?{
}
func?(m?*MyLogger)?WithField(string,?string)?Logger?{
?...
}
func?(m?*MyLogger)?Info(string)?{
}
02 泛型方案
當(dāng)用泛型實(shí)現(xiàn)這一點(diǎn)時(shí),第一個(gè)直接的想法是實(shí)現(xiàn)這樣的東西:
type?GenericLogger[T?any]?interface?{
????WithField(string,?string)?T
????Info(string)
}
然而,如果你仔細(xì)觀察,這本身并不是我們所需要的。我們返回的是 T ,它可以是任何類型但實(shí)際上不只是 GenericLogger!我們這里也不允許引用自己的接口。
這時(shí)候的 MyLogger 可以這么實(shí)現(xiàn),和接口無任何耦合:
type?MyLogger?struct?{
?fields?[]string
}
func?(m?*MyLogger)?WithField(k?string,?v?string)?*MyLogger?{
?m.fields?=?append(m.fields,?k+"="+v)
?return?m
}
func?(m?*MyLogger)?Info(msg?string)?{
?log.Printf("%s?:?%s",?strings.Join(m.fields,?","),?msg)
}
我們需要確保 T 實(shí)際上是我們想要實(shí)現(xiàn)的類型。接口足以做到這一點(diǎn),但在實(shí)際使用時(shí)我們還需要做一些事情:
func?DoStuff[T?GenericLogger[T]](t?T)?{
????t.WithField("go",?"1.18").Info("is?awesome")
}
不知道你能看懂上面的代碼嗎?如果一時(shí)不懂,需要自己琢磨下。你理解后,會(huì)發(fā)現(xiàn)它的工作原理很棒。
以上函數(shù)中,[] 是類型參數(shù),T GenericLogger[T] 中前面的 T 泛型類型,而 GenericLogger[T] 是類型約束,即所有滿足 GenericLogger[T] 接口的類型都符合,這基本是遞歸地告訴 GenericLogger 它本身就是應(yīng)該返回的泛型對(duì)象。最后 () 是普通函數(shù)參數(shù),類型是 T。
基于以上,可以這么使用 DoStuff:
DoStuff(&MyLogger{fields:?make([]string,?0)})
完整可運(yùn)行代碼可以在 playground 查看:https://go.dev/play/p/71m5yxV7ktd?v=gotip。
03 結(jié)論
Go 之前已經(jīng)很強(qiáng)大了,但我相信由于泛型,將會(huì)有新的興趣火花。通過減少冗長(zhǎng),我們將能夠更多地專注于編寫業(yè)務(wù)邏輯,并且有助于在更多領(lǐng)域使用。
結(jié)構(gòu)類型,作為 Go 的核心優(yōu)勢(shì)之一,也將更加強(qiáng)大。
期待 Go1.18 正式發(fā)布,以便我可以在生產(chǎn)環(huán)境中使用它!
我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語言并創(chuàng)建了 Go 語言中文網(wǎng)!著有《Go語言編程之旅》、開源圖書《Go語言標(biāo)準(zhǔn)庫(kù)》等。
堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio
