3

I am new to Golang, after I took a tour of A Tour of Go, I'm trying to make my own thing.

What I want

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.

For example

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);

What I tried

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?

Yami Odymel
  • 1,782
  • 3
  • 22
  • 48

1 Answers1

8

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\n", s.(A).data)
         case B:
             fmt.Printf("B: %d\n", 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\n", s.getDate())
}

func main() {

    classes := []DataGetter{A{data: "first"}, B{data: 2}, A{data: "third"}}
    for _, c := range classes {
        printData(c)
    }
}
Seva
  • 2,388
  • 10
  • 9