Go 中的泛型:改變程式碼可重複使用性
Go 1.18 中引入的泛型徹底改變了編寫可重複使用和類型安全程式碼的方式。泛型帶來了靈活性和強大的功能,同時保持了 Go 的簡單哲學。然而,要了解細微差別、優點以及泛型與傳統方法(如 interface{} )的比較,需要仔細觀察。
讓我們探索泛型的複雜性,深入研究約束,將泛型與介面{}進行比較,並示範它們的實際應用。我們還將討論性能考慮因素和二進制大小的影響。讓我們開始吧!
什麼是泛型?
泛型允許開發人員編寫可以在任何類型上操作的函數和資料結構,同時保持類型安全。泛型不依賴涉及執行時間類型斷言的介面{},而是讓您指定一組約束來規定類型上允許的操作。
文法
func FunctionName[T TypeConstraint](parameterName T) ReturnType { // Function body using T }
T: 型態參數,表示型別的佔位符。
TypeConstraint:將 T 的類型限制為特定類型或一組類型。
parameterName T:參數使用泛型類型T.
ReturnType:函數也可以傳回 T.
類型的值範例
func Sum[T int | float64](a, b T) T { return a + b }
func Sum: 宣告函數名稱 Sum
[T int | float64]: 指定引入T 作為類型參數的類型參數列表,約束為特定類型(int 或float64 )。 Sum 函數只能採用 int 或 float64 參數,不能組合使用,兩者都必須是 int 或 float64。我們將在下面的部分中進一步探討這一點。
(a, b T): 宣告兩個參數a 和b,皆為T 類型(泛型型別) ).
T: 指定函數的回傳類型,與型別參數 T.
相符約束:泛型的建構塊
約束定義哪些操作對於泛型類型有效。 Go 提供了強大的約束工具,包括實驗性約束套件(golang.org/x/exp/constraints)。
內建約束
Go 引入了具有泛型的內建約束,以提供類型安全,同時允許靈活地定義可重複使用和泛型程式碼。這些約束使開發人員能夠對泛型函數或類型中使用的類型強制執行規則。
Go 有以下內建約束
- any:代表任意型別。它是 interface{} 的別名。當不需要約束時使用
func FunctionName[T TypeConstraint](parameterName T) ReturnType { // Function body using T }
- comparable:允許支援相等比較(== 和 !=)的型別。對於映射鍵、重複檢測或相等檢查很有用。這不能用於映射、切片和函數,因為這些類型不支援直接比較。
func Sum[T int | float64](a, b T) T { return a + b }
實驗限制
- constraints.Complex:允許複雜數字類型(complex64 和complex128)。
- constraints.Float:允許浮點數值型別(float32 和 float64)
- constraints.Integer:允許任何有符號和無符號整數(int8、int16、int32、int64、int、uint8、uint16、uint32、uint64 和 uint)
- constraints.Signed:允許任何有符號整數(int8、int16、int32、int64 和 int)
- constraints.Unsigned:允許任何無符號整數(uint8、uint16、uint32、uint64 和 uint)。
- constraint.Ordered:允許進行比較的類型(<.>、>=),支援所有數字類型和字串(int、float64、string 等)。
func PrintValues[T any](values []T) { for _, v := range values { fmt.Println(v) } }
自訂約束
自訂限制是定義泛型類型參數必須滿足的一組類型或類型行為的介面。透過創建您自己的約束,我們可以;
將類型限制為特定子集,例如數字類型。
需要型別來實作特定的方法或行為。
為您的通用函數和類型添加更多控制和特異性。
文法
func CheckDuplicates[T comparable](items []T) []T { seen := make(map[T]bool) duplicates := []T{} for _, item := range items { if seen[item] { duplicates = append(duplicates, item) } else { seen[item] = true } } return duplicates }
範例
import ( "golang.org/x/exp/constraints" "fmt" ) func SortSlice[T constraints.Ordered](items []T) []T { sorted := append([]T{}, items...) // Copy slice sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) return sorted } func main() { nums := []int{5, 2, 9, 1} fmt.Println(SortSlice(nums)) // Output: [1 2 5 9] words := []string{"banana", "apple", "cherry"} fmt.Println(SortSlice(words)) // Output: [apple banana cherry] }
Sum 函數 只能使用 int、int64 和 float64 參數呼叫。
方法的限制
如果你想強制型別必須實作某些方法,你可以使用這些方法來定義它。
type Numeric interface { int | float64 | uint }
Formatter 約束要求任何用作T 的類型必須具有傳回字串.
組合約束自訂限制可以結合型別集與方法要求
type Number interface { int | int64 | float64 } func Sum[T Number](a, b T) T { return a + b }
int、float54),並且需要有 abs 方法。
泛型與介面{}在引入泛型之前,使用interface{}來實現靈活性。然而,這種方法有其限制。
類型安全
- interface{}:依賴執行階段類型斷言,增加執行時間出錯的幾率。
- 泛型:提供編譯時類型安全性,在開發過程中儘早捕捉錯誤。
表現
介面{}:由於額外的執行時間類型檢查,速度較慢。
泛型:更快,因為編譯器會產生特定於類型的最佳化程式碼路徑。
程式碼可讀性
介面{}:通常冗長且不太直觀,使程式碼更難維護。
泛型:更簡潔的語法可以帶來更直覺和可維護的程式碼。
二進位大小
interface{}:產生更小的二進位文件,因為它不會為不同類型重複程式碼。
泛型:由於類型專門化而略微增加二進位大小以獲得更好的性能。
範例
func FunctionName[T TypeConstraint](parameterName T) ReturnType { // Function body using T }
程式碼運作良好,型別斷言是開銷。 Add 函數可以使用任何參數調用,a 和 b 參數可以是不同的類型,但是程式碼會在運行時崩潰。
func Sum[T int | float64](a, b T) T { return a + b }
泛型消除了由不正確的類型斷言引起的運行時恐慌的風險並提高了清晰度。
表現
泛型為每種類型產生專門的程式碼,與介面{}相比,可以帶來更好的執行時間效能。
二進位大小
存在一個權衡:泛型由於每種類型的程式碼重複而增加了二進位大小,但這與好處相比通常可以忽略不計。
Go 泛型的局限性
約束的複雜性: 雖然像 Constraints.Ordered 這樣的限制簡化了常見用例,但定義高度自訂的約束可能會變得冗長。
結構體中沒有類型推論: 與函數不同,您必須為結構體明確指定類型參數。
func PrintValues[T any](values []T) { for _, v := range values { fmt.Println(v) } }
僅限於編譯時約束:Go 泛型專注於編譯時安全,而 Rust 這樣的語言使用生命週期和特徵提供更強大的限制。
讓我們進行基準測試——做得比說的更好
我們將實作一個具有介面{}和通用的簡單佇列,並對結果進行基準測試。
介面{}隊列實現
func CheckDuplicates[T comparable](items []T) []T { seen := make(map[T]bool) duplicates := []T{} for _, item := range items { if seen[item] { duplicates = append(duplicates, item) } else { seen[item] = true } } return duplicates }
通用佇列實現
import ( "golang.org/x/exp/constraints" "fmt" ) func SortSlice[T constraints.Ordered](items []T) []T { sorted := append([]T{}, items...) // Copy slice sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) return sorted } func main() { nums := []int{5, 2, 9, 1} fmt.Println(SortSlice(nums)) // Output: [1 2 5 9] words := []string{"banana", "apple", "cherry"} fmt.Println(SortSlice(words)) // Output: [apple banana cherry] }
type Numeric interface { int | float64 | uint }
結果分析
執行時間:
通用實作比 interface{} 版本快約 63.64%,因為它避免了運行時類型斷言並直接對給定類型進行操作。分配:
Interface{} 版本的分配量增加了 3 倍,這主要是由於插入和檢索值時的裝箱/拆箱。這增加了垃圾收集的開銷。
對於較大的工作負載,例如 100 萬次入隊/出隊操作,效能差距會擴大。具有高吞吐量要求的實際應用程式(例如訊息佇列、作業排程器)可以從泛型中受益匪淺。
最後的想法
Go 中的泛型在功能強大和簡單性之間取得了平衡,為編寫可重複使用和類型安全的程式碼提供了實用的解決方案。雖然不像 Rust 或 C 那樣功能豐富,但與 Go 的極簡主義哲學完美契合。了解約束等約束。有效有序和利用泛型可以大幅提高程式碼品質和可維護性。
隨著泛型的不斷發展,它們注定會在 Go 的生態系統中發揮核心作用。因此,潛入、實驗並擁抱 Go 程式設計類型安全性和靈活性的新時代!
查看 github 儲存庫以取得一些關於泛型的範例。
薩達南多達瓦達卡爾
/
Go泛型
儲存庫包含 go 泛型的工作範例
Go 泛型:綜合範例儲存庫
歡迎來到Go 泛型儲存庫!此儲存庫是 1.18 版本中引入的用於理解、學習和掌握 Go 中泛型的一站式資源。泛型為 Go 帶來了類型參數的強大功能,使開發人員能夠編寫可重複使用且類型安全的程式碼,而不會影響效能或可讀性。
該儲存庫包含精心策劃的範例,涵蓋廣泛的主題,從基本語法到高級模式和實際用例。無論您是初學者還是經驗豐富的 Go 開發人員,此集合都將幫助您在專案中有效地利用泛型。
?裡面有什麼
?基本通用程式
這些範例介紹了泛型的基本概念,幫助您掌握文法和核心功能:
- GenericMap:示範通用映射函數來轉換任何類型的切片。
- 交換:一般交換兩個值的簡單而強大的範例。
- FilterSlice:顯示如何過濾...
以上是Go 中的泛型:改變程式碼可重複使用性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Go語言在構建高效且可擴展的系統中表現出色,其優勢包括:1.高性能:編譯成機器碼,運行速度快;2.並發編程:通過goroutines和channels簡化多任務處理;3.簡潔性:語法簡潔,降低學習和維護成本;4.跨平台:支持跨平台編譯,方便部署。

Golang在並發性上優於C ,而C 在原始速度上優於Golang。 1)Golang通過goroutine和channel實現高效並發,適合處理大量並發任務。 2)C 通過編譯器優化和標準庫,提供接近硬件的高性能,適合需要極致優化的應用。

Golang和Python各有优势:Golang适合高性能和并发编程,Python适用于数据科学和Web开发。Golang以其并发模型和高效性能著称,Python则以简洁语法和丰富库生态系统著称。

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

Golang和C 在性能競賽中的表現各有優勢:1)Golang適合高並發和快速開發,2)C 提供更高性能和細粒度控制。選擇應基於項目需求和團隊技術棧。

goimpactsdevelopmentpositationality throughspeed,效率和模擬性。 1)速度:gocompilesquicklyandrunseff,IdealforlargeProjects.2)效率:效率:ITScomprehenSevestAndardArdardArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdEcceSteral Depentencies,增強的Depleflovelmentimency.3)簡單性。

C 更適合需要直接控制硬件資源和高性能優化的場景,而Golang更適合需要快速開發和高並發處理的場景。 1.C 的優勢在於其接近硬件的特性和高度的優化能力,適合遊戲開發等高性能需求。 2.Golang的優勢在於其簡潔的語法和天然的並發支持,適合高並發服務開發。

Golang和C 在性能上的差異主要體現在內存管理、編譯優化和運行時效率等方面。 1)Golang的垃圾回收機制方便但可能影響性能,2)C 的手動內存管理和編譯器優化在遞歸計算中表現更為高效。
