Reputation: 323
I've only been working with Go for a couple of days. I have a small variety of different structure types defined, each of which contains a date.
Somehow I need to process those structures in date order, but that ordering has to span across the multiple different structure types. In a dynamically typed language like Python, it's easy to just create a hash of all the objects keyed by date (or hash of lists if they're not unique). In C, I can use unions of pointers or void*. But I'm stuck as to how do this in Go.
I guess I could keep a sorted list of each type and do a manual mergesort as I go. Seems klunky?
What I've read about handling this sort of situation seems to point to using interfaces, but I don't really see how to use them in this situation.
For the sake of argument, let's say I have something like:
type A struct {
Date string
Info string
}
type B struct {
Date string
Info int
}
(Though in practice there are more structures, and they are more complex with multiple fields), and just need to print in date order the contents of an (unsorted) array of each of them.
Is there some way to create a list (date, pointer) pairs to a non-uniform object type?
Per first suggestion below:
package main
import "fmt"
type A struct {
Date string
Info string
}
func (x *A) GetDate() string {
return x.Date
}
type B struct {
Date string
Info int
}
func (x *B) GetDate() string {
return x.Date
}
type Dater interface {
GetDate() string
}
type Daters []Dater
func (s Daters) Len() int { return len(s) }
func (s Daters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByDate struct{ Daters }
func (s ByDate) Less(i, j int) bool {
return s.Daters[i].GetDate() < s.Daters[j].GetDate()
}
func main() {
// lista and listb are just examples. They really come from elsewhere
lista := []A{{"2012/08/01", "one"}, {"2012/08/03", "three"}}
listb := []B{{"2012/08/02", 2}, {"2012/08/04", 4}}
x := make([]Dater, len(lista) + len(listb))
index := 0
for i := range(lista) {
x[index] = &lista[i]
index++
}
for i := range(listb) {
x[index] = &listb[i]
index++
}
sort.Sort(ByDate{x})
for _,v := range(x) {
fmt.Printf("%#v\n", v)
}
}
That works! So the basic use of interface is fine, and I'm starting to understand interfaces a little better - thank you!
Note: The creation of x is pretty ugly. I can't see a cleaner / more idiomatic way?
Upvotes: 4
Views: 915
Reputation: 4115
You might be able to use embedding.
You would define a struct that contains nothing but the date, then embed it in the others. That way, you only have to implement GetDate() once. You can also extend the Date struct at any time without modifying the other structs.
package main
type Dater interface {
GetDate() string
}
type Date struct {
Date string
}
func (d *Date) GetDate() string {
return d.Date
}
type A struct {
Date
Info string
}
type B struct {
Date
Info []byte
}
type C struct {
Date
Info int32
}
You can now call GetDate() on A, B, and C.
Upvotes: 0
Reputation: 90
Define a interface (say Dated) with a method (say getDate() that returns Date). Then have all structs (A, B, C) implementing Dated interface. Then you can define use []Dated to hold your type values.
You might want to check package 'time' and 'sort' to simplify the implementation.
Upvotes: 3