I'm trying to write generic function in Golang that would search for a value in slices and in channels in the similar way. Here is an example:
// MinOf returns the smallest number found among the channel / slice contents
func MinOf[T chan int | []int](input T) (result int) {
for _, value := range input {
if result > value {
result = value
}
}
return
}
But I'm getting following compilation error: cannot range over input (variable of type T constrained by chan int|[]int) (T has no core type)
.
I have tried to create common interface, like so:
type Rangable interface {
chan int | []int
}
// MinOf returns the smallest number found among the channel / slice contents
func MinOf[T Rangable](input T) (result int) {
for _, value := range input {
if result > value {
result = value
}
}
return
}
Though, error has changed to cannot range over input (variable of type T constrained by Rangable) (T has no core type)
it remains basically the same...
Is there any way how to solve this task using generics or channels and slices could not be "casted" to same core type?
Thank you for any suggestions and ideas!
CodePudding user response:
You can't do this.
The range
expression must have a core type to begin with. Unions with diverse type terms, do not have a core type because there isn't one single underlying type in common.
You can also intuitively see why range
requires a core type: the semantics of ranging over slices and channels are different.
Ranging over a channel is potentially a blocking operation, ranging over a slice isn't
The iteration variables are different
for i, item := range someSlice {}
With slices i
is the index of type int
and item
is the type of the slice elements.
for item := range someChan {}
With channels, item
is the type of the chan elements and that's the only possible range variable.
The best you can have is a type switch:
func MinOf[T any, U chan T | []T](input U) (result int) {
switch t := any(input).(type) {
case chan T:
// range over chan
case []T:
// range over slice
}
return
}
But again, the behavior of this function (blocking vs. non-blocking) is type dependant, and it's unclear what advantages you get by using generics here.