🌷🍁 博主貓頭虎(🐅🐾)帶您 Go to New World?🍁
🦄 博客首頁——🐅🐾貓頭虎的博客🎐
🐳 《面試題大全專欄》 🦕 文章圖文并茂🦖生動形象🐅簡單易學!歡迎大家來踩踩~🌺
🌊 《IDEA開發秘籍專欄》 🐾 學會IDEA常用操作,工作效率翻倍~💐
🌊 《100天精通Golang(基礎入門篇)》 🐅 學會Golang語言,暢玩云原生,走遍大小廠~💐
🐅🐾貓頭虎建議Go程序員必備技術棧一覽表📖:
??🐳
Go語言開發者必備技術棧??
:
🐹 GoLang | 🌿 Git | 🐳 Docker | ?? Kubernetes | 🔧 CI/CD | ? Testing | 💾 SQL/NoSQL | 📡 gRPC | ?? Cloud | 📊 Prometheus | 📚 ELK Stack
🪁🍁 希望本文能夠給您帶來一定的幫助🌸文章粗淺,敬請批評指正!🐅🐾🍁🐥
文章目錄
- 🐅🐾貓頭虎建議Go程序員必備技術棧一覽表📖:
- 2023年9月26日 Go生態洞察:深入解析類型參數
- 🐾 正文內容
- 🐈 `slices`包函數簽名
- 🐈 簡單的克隆實現
- 🐈 靈活的克隆實現
- 🐈 底層類型約束
- 🐈 類型推斷
- 🐈 類型參數的解構
- 🐾 總結
- 原創聲明
-
原創作者: 貓頭虎
-
作者wx: Libin9iOak
-
作者公眾號: 貓頭虎技術團隊
2023年9月26日 Go生態洞察:深入解析類型參數
🐾 摘要
大家好,我是貓頭虎,今天我們要探討的是Go語言中類型參數的構造和使用。通過深入分析slices.Clone
函數,我們將理解類型參數在Go泛型中的作用和重要性。這不僅是一個技術深度話題,而且對于深入理解Go語言的泛型系統至關重要。
🐾 引言
在Go 1.18的引入泛型之后,類型參數成為了Go語言的一個新亮點。它們提供了編寫更加靈活和可復用代碼的能力。本文將通過Clone
函數的例子,展示如何有效地使用類型參數來增強代碼的通用性和靈活性。
🐾 正文內容
🐈 slices
包函數簽名
Clone
函數非常簡單:它可以復制任何類型的切片。
func Clone[S ~[]E, E any](s S) S {return append(s[:0:0], s...)
}
這個函數之所以有效,是因為對零容量的切片進行追加操作會分配一個新的底層數組。函數體實際上比函數簽名更短,這部分是因為體本身簡短,但也因為簽名較長。接下來,我們將解釋為什么簽名是這樣寫的。
🐈 簡單的克隆實現
我們首先編寫一個簡單的通用Clone
函數。這并不是slices
包中的那一個。我們希望接受任何元素類型的切片,并返回一個新切片。
func Clone1[E any](s []E) []E {// body omitted
}
泛型函數Clone1
有一個類型參數E
。它接受一個類型為E
的切片參數s
,并返回同類型的切片。這個簽名對熟悉Go中泛型的人來說很直接。
然而,這里有一個問題。在Go中,命名的切片類型不常見,但人們確實會使用它們。
// MySlice 是一個具有特殊String方法的字符串切片。
type MySlice []string// String 返回MySlice值的可打印版本。
func (s MySlice) String() string {return strings.Join(s, "+")
}
假設我們想要復制一個MySlice
,然后獲取其排序后的可打印版本。
func PrintSorted(ms MySlice) string {c := Clone1(ms)slices.Sort(c)return c.String() // 編譯失敗
}
不幸的是,這不起作用。編譯器報告錯誤:
c.String undefined (type []string has no field or method String)
🐈 靈活的克隆實現
為了解決這個問題,我們必須編寫一個版本的Clone
,它返回與其參數相同的類型。如果我們做到了這一點,那么當我們用MySlice
類型的值調用Clone
時,它將返回MySlice
類型的結果。
我們知道它應該是這樣的:
func Clone2[S ?](s S) S // 無效
這個Clone2
函數返回與其參數相同類型的值。
🐈 底層類型約束
如錯誤消息所示,答案是添加一個~
。
func Clone5[S ~[]E, E any](s S) S
再次強調,用[S []E, E any]
這樣的類型參數和約束表示,意味著S
的類型參數可以是任何未命名的切片類型,但
不能是定義為切片字面量的命名類型。用[S ~[]E, E any]
,加上~
,意味著S
的類型參數可以是任何底層類型為切片類型的類型。
🐈 類型推斷
現在我們已經解釋了slices.Clone
的簽名,讓我們看看如何通過類型推斷簡化對slices.Clone
的使用。
func Clone[S ~[]E, E any](s S) S
調用slices.Clone
時,將傳遞一個切片給參數s
。類型推斷將允許編譯器推斷出類型參數S
是傳遞給Clone
的切片的類型。然后,類型推斷足夠強大,可以看出E
的類型參數是傳遞給S
的類型參數的元素類型。
🐈 類型參數的解構
我們在這里使用的一般技術,即使用另一個類型參數E
定義一個類型參數S
,是一種在泛型函數簽名中解構類型的方法。通過解構類型,我們可以命名并約束類型的所有方面。
例如,這是maps.Clone
的簽名:
func Clone[M ~map[K]V, K comparable, V any](m M) M
就像slices.Clone
一樣,我們使用一個類型參數來表示參數m
的類型,然后使用另外兩個類型參數K
和V
來解構該類型。
在maps.Clone
中,我們將K
約束為可比較的,因為這是映射鍵類型所必需的。我們可以根據喜好約束組成類型。
func WithStrings[S ~[]E, E interface { String() string }](s S) (S, []string)
這表示WithStrings
的參數必須是一個切片類型,其元素類型具有String
方法。
由于所有Go類型都可以從組成類型構建,我們總是可以使用類型參數來解構這些類型,并根據我們的喜好對它們進行約束。
🐾 總結
總的來說,類型參數在Go泛型中扮演著至關重要的角色。通過精心設計的函數簽名和有效利用類型推斷,我們可以編寫更靈活、更通用的代碼。希望這篇文章能幫助你更好地理解Go中的泛型。這篇文章由貓頭虎的Go生態洞察專欄收錄,更多詳情請點擊這里。
關鍵點 | 描述 |
---|---|
類型參數使用 | 使用類型參數構建靈活通用的函數 |
slices.Clone 分析 | 分析Clone 函數的類型參數和其用法 |
底層類型約束 | 理解底層類型的約束和它們的應用 |
類型推斷 | 探索類型推斷在泛型編程中的作用 |
下一篇預告: 下一篇文章將深入探討Go語言中的類型推斷——《關于類型推斷的一切——還有更多》。我們將繼續深入泛型編程的精髓,探索類型推斷如何簡化我們的編碼過程。敬請期待!�
原創聲明
======= ·
-
原創作者: 貓頭虎
-
作者wx: Libin9iOak
-
作者公眾號: 貓頭虎技術團隊
學習 | 復習 | Go生態 |
---|---|---|
? | ? | ? |
本文為原創文章,版權歸作者所有。未經許可,禁止轉載、復制或引用。
作者保證信息真實可靠,但不對準確性和完整性承擔責任。
未經許可,禁止商業用途。
如有疑問或建議,請聯系作者。
感謝您的支持與尊重。
點擊
下方名片
,加入IT技術核心學習團隊。一起探索科技的未來,洞察Go生態,共同成長。