Golang泛型-简单用例

Say I have 3 structs:

type A struct{
   Foo map[string]string
}

type B struct{
   Foo map[string]string
}

type C struct{
   Foo map[string]string
}

and then I want to create a function that can accept any of those structs:

func handleFoo (){

}

Is there any way to do this with Golang? Something like:

type ABC = A | B | C

func handleFoo(v ABC){
   x: = v.Foo["barbie"] // this would be nice!
}

OK, so let's try an interface:

type FML interface {
  Bar() string
}

func handleFoo(v FML){
   z := v.Bar() // this will compile
   x: = v.Foo["barbie"] // this won't compile - can't access properties like Foo from v
}

In a language which encourages/forces composition, I cannot understand why you can't access properties like Foo.

Because A, B, and C are are all assignable to the same underlying type, you can use a function with an argument of that underlying type: func handleFoo(v struct{ Foo map[string]string })

Run it on the playground.

A limitation of this approach is that methods on A, B and C (even with the same name and signature), are not available in handleFoo.

You can use the interface in this way, add a method GetFoo to get foo of each struct.

type A struct{
    Foo map[string]string
}

func(a *A) GetFoo() map[string]string {
    return a.Foo
}

type B struct{
    Foo map[string]string
}

func(b *B) GetFoo() map[string]string {
    return b.Foo
}

type C struct{
    Foo map[string]string
}

func(c *C) GetFoo() map[string]string {
    return c.Foo
}

type ABC interface {
    GetFoo() map[string][string]
}

func handleFoo (v ABC){
    foo := v.GetFoo()
    x:=foo["barbie"]
}

you can try reflect and pass an interface{} to handleFoo

https://play.golang.org/p/sLyjDvVrUjQ

https://golang.org/pkg/reflect/

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type A struct {
        Foo map[string]string
    }
    type B struct {
        Foo map[string]int
    }
    type C struct {
        Foo map[string]uint
    }
    a := A{
        Foo: map[string]string{"a":"1"},
    }

    b := B{
        Foo: map[string]int{"a":2},
    }

    c := C {
        Foo: map[string]uint{"a":3},
    }


    fmt.Println(a, b, c)

    handleFoo(a)
    handleFoo(b)
    handleFoo(c)

    fmt.Println(a, b, c)
}



func handleFoo(s interface{}) {
    v := reflect.ValueOf(s)
    foo := v.FieldByName("Foo")
    if !foo.IsValid(){
        fmt.Println("not valid")
        return
    }

    switch foo.Type() {
    case reflect.TypeOf(map[string]string{}):
        fmt.Println("is a map[string]string")
        foo.Interface().(map[string]string)["a"] = "100"
    case reflect.TypeOf(map[string]int{}):
        fmt.Println("is a map[string]int")
        foo.Interface().(map[string]int)["a"] =  200
    case reflect.TypeOf(map[string]uint{}):
        fmt.Println("is a map[string]uint")
        foo.Interface().(map[string]uint)["a"] =  300
    }
}