进行类型转换-使用共享接口对2个不同接口的切片进行排序

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 Foos and a slice of Bars. 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))
}

The Go playground

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.