Generics With closure return

package main

import "fmt"

func chunker[T any]() func([]T, int) [][]T {
	return func(ar []T, size int) [][]T {
		var finalAr [][]T
		for i := 0; i < len(ar); i += size {
			end := i + size
			if end > len(ar) {
				end = len(ar)
			}
			finalAr = append(finalAr, ar[i:end])
		}
		return finalAr
	}
}
func main() {
	xI := []int{1, 2, 3, 0, 0, 5, 6, 4, 7, 8, 9, 10}
	fmt.Println(chunker()(xI, 3))
}

This throws

./prog.go:20:21: cannot infer T (prog.go:5:14)

Its equivalent without closure return works fine

package main

import "fmt"

func chunker[T any](ar []T, size int) [][]T {
	var finalAr [][]T
	for i := 0; i < len(ar); i += size {
		end := i + size
		if end > len(ar) {
			end = len(ar)
		}
		finalAr = append(finalAr, ar[i:end])
	}
	return finalAr
}
func main() {
	xI := []int{1, 2, 3, 0, 0, 5, 6, 4, 7, 8, 9, 10}
	xS := []string{"a", "b", "c", "c", "d", "e", "f", "g", "h"}

	fmt.Println(chunker(xI, 3))
	fmt.Println(chunker(xS, 4))
}

Gives this

[[1 2 3] [0 0 5] [6 4 7] [8 9 10]]
[[a b c c] [d e f g] [h]]

Which is expected

How can I make the closure one work

The answer to this question is pretty simple, you need to explicitly pass the underlying type on the slice to your function. Just change chunker()(xI, 3) to chunker[int]()(xI, 3). In this case compiler will understand what kind of data you are trying to process with your generic and won’t through an error.

1 Like

Thanks for reply and it’s finally working.

What do I do for the size parameter to work when parameterized as type T instead of int,

If I put T instead of int it throws this error

./prog.go:8:28: invalid operation: i += size (mismatched types int and T)
./prog.go:9:11: invalid operation: i + size (mismatched types int and T)

package main

import "fmt"

func chunker[T any]() func([]T, T) [][]T {
	return func(ar []T, size T) [][]T {
		var finalAr [][]T
		for i := 0; i < len(ar); i += size {
			end := i + size
			if end > len(ar) {
				end = len(ar)
			}
			finalAr = append(finalAr, ar[i:end])
		}
		return finalAr
	}
}
func main() {
	xI := []int{1, 2, 3, 0, 0, 5, 6, 4, 7, 8, 9, 10}
	fmt.Println(chunker[int]()(xI, 3))
}```

I don’t think you can do a lot with it here. Since you define i as the counter for the loop and its type is int. You need to be sure size variable will also be a numeric type. If you want to make it generic (but I don’t recommend), you need to do type assertion inside the closure, something like:

var sizeInt = any(size).(int)
for i := 0; i < len(ar); i += sizeInt {

But as I stated above, it’s not a good thing, since your function will panic as soon as you pass something what cannot be asserted as integer. The size is always something numerical and can be left to be int as it is right now. For example you can check the new slices package in go, where they add generic functions to work with slices of different types. In particular Delete function all requested borders of the slice are int.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.