I am creating a data structure using Go generics.
The use case is to write a Reduce function that takes a slice of a defined type, applies a reduce function to each element of the slice and returns a value of the defined type.
type MyType[T any] struct{
I T
}
// I want to write something like this
func (m *MyType[[]T]) Reduce(init T, fnReduce func(T, T)T) (*MyType[T]) {
acc := init
for _, v := range m.I {
acc = fnReduce(acc, v)
}
return &MyType[T]{I : acc}
}
Go compiler does not allow to give the type parameter to the receiver as:
m *MyType[[]T]
What is a way to solve this?
If you want to have a method on a slice to reduce it, define MyStruct
as a slice of T
:
type MyType[T any] []T
func (m MyType[T]) Reduce(init T, fnReduce func(acc, elem T) (result T)) T {
res := init
for _, v := range m {
res = fnReduce(res, v)
}
return res
}
Here an example on the Playground.
In case you need to be able to add other fields to MyStruct
apart from the slice itself, a struct with a field containing the slice is also an option. (New
func to populate the private slice field from outside the package.)
func NewMyType[T any](sl []T) MyType[T] {
return MyType[T]{sl: sl}
}
type MyType[T any] struct {
sl []T
}
func (m MyType[T]) Reduce(init T, fnReduce func(acc, elem T) (result T)) T {
res := init
for _, v := range m.sl {
res = fnReduce(res, v)
}
return res
}
On the issue stated in the comment:
func reduce[T any](sl []T, init T, fnReduce func(acc, elem T) (result T)) T {
res := init
for _, v := range sl {
res = fnReduce(res, v)
}
return res
}
type MyI[T any] interface {
Reduce(init T, reduce func(acc, elem T) (result T)) T
}
type MySliceType[T any] struct {
data []T
}
func (m MySliceType[T]) Reduce(init T, reduce func(acc, elem T) T) T {
res := init
for _, v := range m.data {
res = reduce(res, v)
}
return res
}
type MyType[T any] struct {
data T
}
func (m MyType[T]) Reduce( T, func(acc, elem T) T) T {
return m.data
}
We have a common Reduce
function here, just in case we don't have a slice it just return m.data
. If we have a slice, it actually applies the reduce function.
(The example doesn't make too much sense, but I hope the idea comes across.)