Go語言泛型打造優(yōu)雅的切片工具庫
什么是泛型
泛型是一種編程范式,允許開發(fā)者在編寫代碼時定義通用的類型參數(shù),而不是具體的類型。通過泛型,可以編寫出能夠處理多種數(shù)據(jù)類型的代碼,而無需為每種類型重復編寫相同的邏輯。例如,一個泛型函數(shù)可以同時處理整數(shù)、浮點數(shù)、字符串等多種類型的數(shù)據(jù)。
泛型解決了什么問題
在 Go 語言引入泛型之前,開發(fā)者在處理不同數(shù)據(jù)類型時,往往需要編寫重復的代碼。例如,實現(xiàn)一個排序算法,可能需要為整數(shù)、浮點數(shù)、字符串等分別編寫不同的版本。這種重復不僅增加了代碼量,也降低了代碼的可維護性。引入泛型后,可以通過定義一個通用的類型參數(shù),編寫一個通用的排序函數(shù),從而提高代碼的復用性和可維護性。
基于泛型的常見切片操作
博主結(jié)合自身在實際開發(fā)當中的經(jīng)驗,將利用Go泛型,封裝一些常見的切片操作。本篇博客所編寫的代碼,皆可直接集成到生產(chǎn)環(huán)境的公共代碼庫中。各位小伙伴可以根據(jù)自身項目的實際情況,將對你們項目有幫助的代碼遷移到自己的項目當中。
1.反轉(zhuǎn)切片(改變原切片)
func ReverseOriginalSlice[T any](s []T) { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } }
2.反轉(zhuǎn)切片(不改變原切片)
func ReverseSlice[T any](s []T) []T { res := make([]T, len(s)) copy(res, s) ReverseOriginalSlice(res) // 調(diào)用之前的ReverseOriginalSlice函數(shù) return res }
3.切片分批
func BatchSlice[T any](s []T, size int) [][]T { var batchSlice [][]T // 遍歷切片,每次取 size 個元素 for i := 0; i < len(s); i += size { end := i + size // 處理最后一批元素數(shù)量不足 size 的情況 if end > len(s) { end = len(s) } // 將當前批次的元素添加到結(jié)果中 batchSlice = append(batchSlice, s[i:end]) } return batchSlice }
4.合并切片
func MergeSlices[T any](slices ...[]T) []T { totalLength := 0 for _, slice := range slices { totalLength += len(slice) } res := make([]T, 0, totalLength) for _, slice := range slices { ls := make([]T, len(slice)) copy(ls, slice) res = append(res, ls...) } return res }
5.切片去重
func UniqueSlice[T comparable](s []T) []T { seen := make(map[T]bool) res := make([]T, 0, len(s)) for _, v := range s { if !seen[v] { // 如果元素未出現(xiàn)過,添加到結(jié)果切片中 res = append(res, v) seen[v] = true } } return res }
6.切片轉(zhuǎn)哈希表
func SliceToMap[T any, K comparable](s []T, keyFunc func(T) K) map[K]T { res := make(map[K]T) for _, v := range s { key := keyFunc(v) res[key] = v } return res }
7.哈希表轉(zhuǎn)切片
func MapToSlice[K comparable, V any, T any](m map[K]V, extractor func(V) T) []T { res := make([]T, 0, len(m)) for _, v := range m { res = append(res, extractor(v)) } return res }
8.獲取切片元素的某個字段
func GetListField[T any, V any](s []T, fieldFunc func(T) V) []V { res := make([]V, 0, len(s)) for _, item := range s { res = append(res, fieldFunc(item)) } return res }
9.切片全部元素滿足條件判斷
func SliceMatchCondition[T any](s []T, condition func(T) bool) bool { for _, v := range s { if !condition(v) { return false } } return true }
10.取切片交集
func Intersection[T comparable](slices ...[]T) []T { if len(slices) == 0 { return nil } // 使用 map 來存儲第一個切片中的元素 intersectionMap := make(map[T]int) for _, v := range slices[0] { intersectionMap[v]++ } // 遍歷后續(xù)切片,更新交集 for _, slice := range slices[1:] { m := make(map[T]int) for _, v := range slice { if _, exists := intersectionMap[v]; exists { m[v]++ } } intersectionMap = m } // 將交集的元素收集到結(jié)果切片中 var res []T for k := range intersectionMap { res = append(res, k) } return res }
11.取切片并集
func Union[T comparable](slices ...[]T) []T { elementMap := make(map[T]struct{}) for _, slice := range slices { for _, v := range slice { elementMap[v] = struct{}{} } } var res []T for k := range elementMap { res = append(res, k) } return res }
代碼合集
我將上述所有代碼集成到一個slices.go文件當中。如果各位小伙伴們的項目有需要,只需將以下代碼完整拷貝到你們項目的基礎(chǔ)代碼工具庫即可。
slices.go
package slices // 反轉(zhuǎn)切片(改變原切片) func ReverseOriginalSlice[T any](s []T) { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } } // 反鉆切片(不改變原切片) func ReverseSlice[T any](s []T) []T { res := make([]T, len(s)) copy(res, s) ReverseOriginalSlice(res) return res } // 切片分批 func BatchSlice[T any](s []T, size int) [][]T { var batchSlice [][]T for i := 0; i < len(s); i += size { end := i + size if end > len(s) { end = len(s) } batchSlice = append(batchSlice, s[i:end]) } return batchSlice } // 合并切片 func MergeSlices[T any](slices ...[]T) []T { totalLength := 0 for _, slice := range slices { totalLength += len(slice) } res := make([]T, 0, totalLength) for _, slice := range slices { ls := make([]T, len(slice)) copy(ls, slice) res = append(res, ls...) } return res } // 切片去重 func UniqueSlice[T comparable](s []T) []T { seen := make(map[T]bool) res := make([]T, 0, len(s)) for _, v := range s { if !seen[v] { res = append(res, v) seen[v] = true } } return res } // 切片轉(zhuǎn)哈希表 func SliceToMap[T any, K comparable](s []T, keyFunc func(T) K) map[K]T { res := make(map[K]T) for _, v := range s { key := keyFunc(v) res[key] = v } return res } // 哈希表轉(zhuǎn)切片 func MapToSlice[K comparable, V any, T any](m map[K]V, extractor func(V) T) []T { res := make([]T, 0, len(m)) for _, v := range m { res = append(res, extractor(v)) } return res } // 獲取切片元素的某個字段 func GetListField[T any, V any](s []T, fieldFunc func(T) V) []V { res := make([]V, 0, len(s)) for _, item := range s { res = append(res, fieldFunc(item)) } return res } // 切片全部元素滿足條件判斷 func SliceMatchCondition[T any](s []T, condition func(T) bool) bool { for _, v := range s { if !condition(v) { return false } } return true } // 取切片交集 func Intersection[T comparable](slices ...[]T) []T { if len(slices) == 0 { return nil } intersectionMap := make(map[T]int) for _, v := range slices[0] { intersectionMap[v]++ } for _, slice := range slices[1:] { m := make(map[T]int) for _, v := range slice { if _, exists := intersectionMap[v]; exists { m[v]++ } } intersectionMap = m } var res []T for k := range intersectionMap { res = append(res, k) } return res } // 取切片并集 func Union[T comparable](slices ...[]T) []T { elementMap := make(map[T]struct{}) for _, slice := range slices { for _, v := range slice { elementMap[v] = struct{}{} } } var res []T for k := range elementMap { res = append(res, k) } return res }
總結(jié)
本文使用Go泛型,對常見的切片操作進行了封裝,整理出了一個切片工具庫slices.go。
到此這篇關(guān)于Go語言泛型打造優(yōu)雅的切片工具庫的文章就介紹到這了,更多相關(guān)Go泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!