|
> If you have an interface with a single method, or something with a single varying piece of behavior, please strongly consider accepting a function instead. Agreed. And if you prefer methods to functions, you can define methods on such a function type!
In my LINQ in Go (https://github.com/nukata/linq-in-go), I define a higher order function type: type Enumerator[T any] func(yield func(element T))
and several methods on it, for example, // Where creates an Enumerator which selects elements by appling
// predicate to each of them.
func (loop Enumerator[T]) Where(predicate func(T) bool) Enumerator[T] {
return func(yield func(T)) {
loop(func(element T) {
if predicate(element) {
yield(element)
}
})
}
}
Naturally, if you need another type parameter for a method, you must define it as a function. For example, // Select creates an Enumerator which applies f to each of elements.
func Select[T any, R any](f func(T) R, loop Enumerator[T]) Enumerator[R] {
return func(yield func(R)) {
loop(func(element T) {
value := f(element)
yield(value)
})
}
}
Now, with the function which converts a slice to an Enumerator, // From creates an Enumerator from a slice.
func From[T ~[]E, E any](x T) Enumerator[E] {
return func(yield func(E)) {
for _, element := range x {
yield(element)
}
}
}
you can write the following: seq := Select(func(e int) int { return e + 100 },
From([]int{
7, 8, 9,
})).Where(func(e int) bool {
return e%2 != 0
})
seq(func(e int) {
Println(e)
})
// Output:
// 107
// 109
|