Go 泛型玩出花,詳解新提案 Switch Type!
本文轉(zhuǎn)載自微信公眾號(hào)「腦子進(jìn)煎魚了」,作者陳煎魚。轉(zhuǎn)載本文請(qǐng)聯(lián)系腦子進(jìn)煎魚了公眾號(hào)。
大家好,我是煎魚。
前面寫過(guò)好幾篇 Go 泛型的語(yǔ)法、案例介紹,新的一手 Go 消息。實(shí)際上,隨著一些提案被接受,新的提案也逐漸冒出。
這不,我發(fā)現(xiàn)有了泛型后,大家可以更進(jìn)一步玩出花來(lái)了??吹搅艘粋€(gè) ”新“ 提案《proposal: spec: generics: type switch on parametric types[1]》,講的就是增加泛型后的參數(shù)類型上的類型開(kāi)關(guān)訴求。
跟著煎魚一起掌握新的 Go 知識(shí)吧!
新提案
新的提案內(nèi)容是希望增加一個(gè)新的變種語(yǔ)句,允許在 switch 語(yǔ)句的類型中使用泛型時(shí),能夠進(jìn)一步便捷的約束其類型參數(shù)。
例如:
- switch type T {
- case A1:
- case A2, A3:
- ...
- }
也就是 switch-type 語(yǔ)句的 T 類型可以是一個(gè)泛型的類型參數(shù),case 所對(duì)應(yīng)的的類型可以是任何類型,包括泛型的約束類型。
假設(shè)類型 T 的類型有可能是以下類型:
- interface{
- C
- A
- }
可以借助泛型的近似元素來(lái)約束:
- interface{
- C
- A1 | A2 | ... | An
- }
甚至還可以在 case 上有新的寫法:
- case interface {~T}:
在支持泛型后,switch 在 type 和 case 上會(huì)存在很多種可能性,需要進(jìn)行具體的特性支持,這個(gè)提案就是為此出現(xiàn)。
實(shí)際案例
案例一:多類型元素
- type Stringish interface {
- string | fmt.Stringer
- }
- func Concat[S Stringish](x []S "S Stringish") string {
- switch type S {
- case string:
- ...
- case fmt.Stringer:
- ...
- }
- }
類型 S 能夠支持 string 和 fmt.Stringer 類型,case 配套對(duì)應(yīng)實(shí)現(xiàn)。
案例二:近似元素
- type Constraint interface {
- ~int | ~int8 | ~string
- }
- func ThisSyntax[T Constraint]( "T Constraint") {
- switch type T {
- case ~int | ~int8:
- ...
- case ~string:
- ...
- }
- }
- func IsClearerThanThisSyntax[T Constraint]( "T Constraint") {
- switch type T {
- case interface{~int | ~int8 }:
- ...
- case interface{ ~string }:
- ...
- }
- }
類型 T 可能有很多類型,程序中用到了近似元素,也就是基礎(chǔ)類型是 int、int8、string,這些類型中的任何一種都能夠滿足這個(gè)約束。
為此,switch-type 支持了,case 也要配套支持該特性。
爭(zhēng)議點(diǎn)
看到這里可能大家也想到了,這個(gè)味道很似曾相識(shí),好像某個(gè)語(yǔ)法能夠支持。因此,這個(gè)提案下最有爭(zhēng)議的,就是與原有的類型斷言的重復(fù)。
原有的類型斷言如下:
- switch T.(type) {
- case string:
- ...
- default:
- ...
- }
新的類型判別如下:
- switch type T {
- case A1:
- case A2, A3:
- ...
- }
這么咋一看,其實(shí)類型斷言的完全可以取代新的,那豈不是重復(fù)建設(shè),造輪子了?
其實(shí)是沒(méi)有完全取代的。差異點(diǎn)如下:
- type ApproxString interface { ~string }
- func F[T ApproxString](v T "T ApproxString") {
- switch (interface{})(v).(type) {
- case string:
- fmt.Println(v)
- default:
- panic("腦子沒(méi)進(jìn)煎魚")
- }
- }
- type MyString string
- func main() {
- F(MyString("腦子進(jìn)煎魚了"))
- }
看出來(lái)差別在哪了嗎,答案是什么?
答案是:會(huì)拋出恐慌(panic)。
你可能糾結(jié)了,問(wèn)題出在哪里?這傳入的 ”腦子進(jìn)煎魚了“ 的類型是 MyString,他的基礎(chǔ)類型是 string 類型,也滿足 ApproxString 類型的近似類型 ~string 的要求,怎么就不行了...
根本原因是因?yàn)樗念愋褪?interface,而非 string 類型。所以走到了 defalut 分支的恐慌。
總結(jié)
今天給大家介紹了 Go 泛型的最新消息,在上一個(gè)提案被合并后,該提案也有一些新的動(dòng)靜,不過(guò) Go 官方表態(tài),會(huì)等熟練掌握泛型實(shí)踐后,再繼續(xù)推動(dòng)該提案。
我相信原有的 switch.(type) 和 switch type 很大概率在 Go 底層會(huì)變成同一個(gè)邏輯塊處理,再逐漸過(guò)渡。
這個(gè)提案的目的還是為了解決若干引入泛型后,所帶入的 BUG/需求,正正是需要新的語(yǔ)法結(jié)構(gòu)來(lái)解決的。
你對(duì)此有什么看法呢,歡迎在評(píng)論區(qū)留言和交流:)
參考資料
[1]proposal: spec: generics: type switch on parametric types: https://github.com/golang/go/issues/45380




























