在没有switch语句的情况下在运行时进行选择实现

I want to select implementation of an interface at runtime, using provided string. I don't want to use switch statement - the code should be generic and work with any new struct implementing the interface without need to modification (open/closed).

Let's say I have following structure:

type Fooer interface {
    Foo()
}

type A struct{}

func (_ *A) Foo() {
    fmt.Println("Calling A")
}

type B struct{}

func (_ *B) Foo() {
    fmt.Println("Calling B")
}

type C struct{}

func (_ *C) Foo() {
    fmt.Println("Calling C")
}

Then, I'd like to do something like:

func main() {
    // let's pretend it's user input
    input := []string{"C", "A", "C"}

    for _, className := range input {
        // struct := StructFromName(className)
        // struct.Foo()
    }
}

To print:

Calling C
Calling A
Calling C

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

To my disappointment, go runtime keeps no registry of struct names and as a result, no StructFromName(className) is available. I wouldn't like to create such registry by my own as well. Disclaimer: I write mainly in java and I have OOP habits, so I expected something as easy as

Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
Foo foo = (Foo) object;
foo.Foo();

I tried another approach, with methods instead of interface, and it works but it feels hacky and non-idiomatic:

type Hack struct{}

func (_ *Hack) FooA() {
    fmt.Println("Calling A")
}

func (_ *Hack) FooB() {
    fmt.Println("Calling B")
}

func (_ *Hack) FooC() {
    fmt.Println("Calling C")
}

func main() {
    hack := &Hack{}

    // let's pretend it's user input
    input := []string{"FooC", "FooA", "FooC"}

    for _, funcName := range input {
        reflect.ValueOf(hack).MethodByName(funcName).Call(nil)
    }
}

https://play.golang.org/p/3ueEuVV2Hx9

Is there a better way?

The best approach to this type of thing is indeed a registry. I suggest using the registry in the database/sql package of the standard library for guidance.

Each SQL driver (MySQL, PostgreSQL, etc), registers itself in its own init() function by calling sql.Register.

This makes for a clean dependency tree (no circular dependencies), and allows for ad-hoc implementations of your type, possibly even from third parties.