What is a generic
Generics are programming paradigms that allow developers to define common type parameters rather than specific types when writing code. Generics allow you to write code that can handle multiple data types without repeatedly writing the same logic for each type. For example, a generic function can process multiple types of data such as integers, floating point numbers, strings, etc. at the same time.
What problems does generics solve
Before the introduction of generics in Go language, developers often needed to write duplicate code when dealing with different data types. For example, implementing a sorting algorithm may require writing different versions for integers, floating point numbers, strings, etc. This repetition not only increases the amount of code, but also reduces the maintainability of the code. After introducing generics, you can define a common type parameter and write a general sorting function to improve the reusability and maintainability of the code.
Common slicing operations based on generics
Based on his own experience in actual development, the blogger will use Go generics to encapsulate some common slice operations. All the codes written in this blog are OKPublic code library directly integrated into production environmentsmiddle. Dear friends, you can migrate the code that is helpful to your project to your own project based on the actual situation of your project.
1. Invert the slice (change the original slice)
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. Invert the slice (not changing the original slice)
func ReverseSlice[T any](s []T) []T { res := make([]T, len(s)) copy(res, s) ReverseOriginalSlice(res) // Call the ReverseOriginalSlice function before return res }
3. Slice in batches
func BatchSlice[T any](s []T, size int) [][]T { var batchSlice [][]T // traverse the slice, and take size elements each time for i := 0; i < len(s); i += size { end := i + size // Handle the situation where the last batch of elements is insufficient in size if end > len(s) { end = len(s) } // Add the elements of the current batch to the result batchSlice = append(batchSlice, s[i:end]) } return batchSlice }
4. Merge slices
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. Slice and remove heavy
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] { // If the element has not appeared, add to the result slice res = append(res, v) seen[v] = true } } return res }
6. Slice to hash table
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. To slice hash table
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. Get a field of the slice element
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. Slicing all elements meet the conditions
func SliceMatchCondition[T any](s []T, condition func(T) bool) bool { for _, v := range s { if !condition(v) { return false } } return true }
10. Take slices and intersect
func Intersection[T comparable](slices ...[]T) []T { if len(slices) == 0 { return nil } // Use map to store elements in the first slice intersectionMap := make(map[T]int) for _, v := range slices[0] { intersectionMap[v]++ } // traverse the subsequent slices and update the intersection for _, slice := range slices[1:] { m := make(map[T]int) for _, v := range slice { if _, exists := intersectionMap[v]; exists { m[v]++ } } intersectionMap = m } // Collect the intersection elements into the result slice var res []T for k := range intersectionMap { res = append(res, k) } return res }
11. Take slices and gather
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 }
Code collection
I integrated all the above code into onein the file. If you guys need your project, just copy the following code to your project's basic code tool library.
package slices // Invert the slice (change the original slice)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] } } // Back-drilling slice (no change the original slice)func ReverseSlice[T any](s []T) []T { res := make([]T, len(s)) copy(res, s) ReverseOriginalSlice(res) return res } // Slice in batchesfunc 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 } // Merge slicesfunc 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 } // Slice and remove heavyfunc 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 } // Slice to hash tablefunc 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 } // hash table to slicefunc 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 } // Get a field of the slice elementfunc 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 } // All elements of the slice meet the conditionsfunc SliceMatchCondition[T any](s []T, condition func(T) bool) bool { for _, v := range s { if !condition(v) { return false } } return true } // Get slices and intersectfunc 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 } // Take slices and gatherfunc 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 }
Summarize
This article uses Go generics to encapsulate common slice operations and organizes a slice tool library。
This is the end of this article about creating an elegant slicing tool library for Go generics. For more related Go generic content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!