The example below contains 2 interfaces Foo
and Bar
that both implement the same interface Timestamper
. It also contains the type ByTimestamp
that implements sort.Interface.
As shown in the function main
, I would like to use the type ByTimestamp
to sort both a slice of Foo
s and a slice of Bar
s. However, the code will not compile because it cannot convert foos (type []Foo) to type ByTimestamp
and it cannot convert bars (type []Bar) to type ByTimestamp
.
Is it possible to sort 2 slices of different interfaces that both implement the same interface with a single type that implements sort.Interface
?
package main
import (
"sort"
)
type Timestamper interface {
Timestamp() int64
}
type ByTimestamp []Timestamper
func (b ByTimestamp) Len() int {
return len(b)
}
func (b ByTimestamp) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b ByTimestamp) Less(i, j int) bool {
return b[i].Timestamp() < b[j].Timestamp()
}
type Foo interface {
Timestamper
DoFoo() error
}
type Bar interface {
Timestamper
DoBar() error
}
func getFoos() (foos []Foo) {
// TODO get foos
return
}
func getBars() (bars []Bar) {
// TODO get bars
return
}
func main() {
foos := getFoos()
bars := getBars()
sort.Sort(ByTimestamp(foos))
sort.Sort(ByTimestamp(bars))
}
Yes, it is possible to sort different types using one sort.Interface
. But not the way you were trying to do it. Current Go specification doesn't allow converting one slice type to another. You have to convert each item.
Here's a helper function that does it using reflection:
// ByTimestamp converts a slice of Timestamper into a slice
// that can be sorted by timestamp.
func ByTimestamp(slice interface{}) sort.Interface {
value := reflect.ValueOf(slice)
length := value.Len()
b := make(byTimestamp, 0, length)
for i := 0; i < length; i++ {
b = append(b, value.Index(i).Interface().(Timestamper))
}
return b
}
See the full example here.
And, if you only have a couple of types, then it might make sense to do type-specific conversions instead.