441 words, 3 min read

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.

@MattJamesBoyle

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 ChunkT any [][]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 GetT any *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 UniqueT comparable []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 IntersectionT comparable []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.