Below is a generic split function that splits a slice into several equal sized (except maybe the last partition) slices based on input size:
func split[S ~[]T, T any](slc S, size int) []S {
slices := make([]S, 0, len(slc)/size+1)
for len(slc) > 0 {
if size > len(slc) {
size = len(slc)
}
slices = append(slices, slc[:size])
slc = slc[size:]
}
return slices
}
The generic type parameter S has type ~[]T where T is any. This works as expected.
The ~ is required to handle defined types, for example:
type X []string
Without the ~ in S ~T[], split wouldn't work on an argument of type X (it would still work on a []string).
Then there is this other splitAny function:
func splitAny[S ~[]any](slc S, size int) []S {
slices := make([]S, 0, len(slc)/size+1)
for len(slc) > 0 {
if size > len(slc) {
size = len(slc)
}
slices = append(slices, slc[:size])
slc = slc[size:]
}
return slices
}
This function works on a []interface{} or anything that is type []interface{}.
My question is, what exactly is the mechanism that the compiler is taking here to produce type safe code? Why are the two split function not equivalent. More generally, why can't splitAny work with, for example, a []string?