I am new to Golang, after I took a tour of A Tour of Go, I'm trying to make my own thing.
I want to put different types of the structs into a single slice (or struct?),
so I can use a for
loop to pass each struct to a function.
In PHP I can store my classes in an array and pass each of them to foobar()
like this:
$classes = [$A, $B, $C, $D]; // $A, $B, $C, $D are classes (called `struct` in Golang).
foreach ($classes as $class)
foobar($class);
I tried to do the same in Golang, and I hope it looks like this:
A{B{}, C{}, D{}}
Since I failed on using slice
, I decided to use struct
to hold my structs
:
type A struct {
B
C
D
}
type B struct {
Date string
}
type C struct {
Date string
}
type D struct {
Date string
}
func main() {
// Using reflect to loop the A struct:
// http://stackoverflow.com/questions/18926303/iterate-through-a-struct-in-go
v := reflect.ValueOf(A{})
for i := 0; i < v.NumField(); i++ {
foobar(v.Field(i).Interface()) // Passing each struct to the `foobar()` function
}
}
But it seems like I'm actually doing embedding instead of storing them, any suggestions please?
I think interface{} is what you're after. For example like this:
type A struct {
data string
}
type B struct {
data int
}
func printData(s interface{}) {
switch s.(type) {
case A:
fmt.Printf("A: %s
", s.(A).data)
case B:
fmt.Printf("B: %d
", s.(B).data)
}
}
func main() {
classes := []interface{}{A{data: "first"}, B{data: 2}, A{data: "third"}}
for _, c := range classes {
printData(c)
}
}
This is probably as close as you can get to "duck typing" in go.
Though if your structs are really that similar, you might better off defining a common interface instead and implementing that interface for each struct. Here is same example using interfaces:
type DataGetter interface {
getDate() string
}
type A struct {
data string
}
func (a A) getDate() string {
return a.data
}
type B struct {
data int
}
func (b B) getDate() string {
return fmt.Sprintf("%d", b.data)
}
func printData(s DataGetter) {
fmt.Printf("%s
", s.getDate())
}
func main() {
classes := []DataGetter{A{data: "first"}, B{data: 2}, A{data: "third"}}
for _, c := range classes {
printData(c)
}
}