We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
I recently saw a discussion on the Twitter Golang community about the use-cases for generics in Go. I thought it would be interesting to share my thoughts on the subject and show some examples of how I use generics in my projects.
The discussion started of with:
So Generics have been part of Go officially for a year or so now. Is anyone meaningfully using them?
I have still not found myself or my team using them, perhaps it's an "old habit die hard" sort of thing but I still kind of wish they were not part of the language. The only use I have seen of them in the wild has been in open source and I have found often it is early and unnecessary abstractions.
Chunking a slice
The first example is a function that takes a slice and returns a slice of slices. The function splits the input slice into chunks of a given size.
func Chunk[T any](slice []T, chunkSize int) [][]T {
var chunks [][]T
for i := 0; i < len(slice); i += chunkSize {
end := i + chunkSize
if end > len(slice) {
end = len(slice)
}
chunks = append(chunks, slice[i:end])
}
return chunks
}
Getting an item from a slice given an index, returning nil
if it doesn't exist
The second example is a function that takes a slice and an index and returns the item at that index. If the index is out of bounds, it returns nil
.
func Get[T any](s []T, i int) *T {
if i < 0 || i >= len(s) {
return nil
}
return &s[i]
}
Removing duplicates from a slice
The third example is a function that takes a slice and returns a slice with all the duplicates removed.
func Unique[T comparable](s []T) []T {
inResult := make(map[T]bool)
var result []T
for _, str := range s {
if _, ok := inResult[str]; !ok {
inResult[str] = true
result = append(result, str)
}
}
return result
}
Get the intersection of multiple slices
The fourth example is a function that takes multiple slices and returns a slice with the intersection of all the slices.
func Intersection[T comparable](slices ...[]T) []T {
counts := map[T]int{}
result := []T{}
for _, slice := range slices {
for _, val := range slice {
counts[val]++
}
}
for val, count := range counts {
if count == len(slices) {
result = append(result, val)
}
}
return result
}
I must admin that with the new slices
and maps
packages that were introduced with Go 1.21, I tend to use less generics in my own code. Without generics though, packages like slices
and maps
would not be possible.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.