I was recently hacking on some Golang code and came up with this switch / case statement:
switch what {
case "Type1" : names[name] = new(Type1)
case "Type2" : names[name] = new(Type2)
case "Type3": names[name] = new(Type3)
}
Depending upon what`s value, I want to create a new type struct instance. How would this be possible without a switch / case statement, or equivalent if / else statement? I was thinking that what could be the key to a hash table and the type of type could be the value. But what is the Golang syntax for new(indirect type) ?
Similarly, let’s say that we want to call one of n interface functions on one of those new type structs, this can be also done with a switch / case statement as follows:
type TypeStar interface {
Func1()
Func2()
}
type Type1 struct {}
func (a *Type1) Func() { fmt.Printf ("func1,type1") }
func (a *Type1) Func2() { fmt.Printf ("func2,type1") }
type Type2 struct {}
func (a *Type2) Func1() { fmt.Printf ("func1,type2") }
func (a *Type2) Func2() { fmt.Printf ("func2,type2") }
type Type3 struct {}
func (a *Type3) Func1() { fmt.Printf ("func1,type3") }
func (a *Type3) Func2() { fmt.Printf ("func2,type3") }
...
if object, ok := names[name]; ok {
switch what {
case "func1" : object.func1()
case "func2" : object.func2()
}
}
But how change this code to eliminate the switch / case statement and use e.g. a hash table instead, e.g. what is the Golang syntax to store the indirect interface function as a hash table value so that the interface function can be looked up in the hash table and then called?
The way you’re doing it (or with a map, or if … else, etc.) is the only way you can go from a string to a type. You can use the reflect package to “parameterize” the type, but you must first have a reference to the type. i.e., given this code:
type MyType struct{}
func main() {
x := newOf("MyType")
}
The only way for newOf to work is if you have some registry that maps names to types. This is the way, for example, the database/sql driver packages work: The reason for the _ imports for driver packages is required is to ensure they’re registered in some global database/sql driver registry, like with an init function.
Sorry, I expanded my original question while you were replying. It would be great if you could offer more wisdom regarding the second part of the question too. Thanks!
With the first suggestion then I was confused at the start, thinking that “newOf()” was a regular Golang built-in function. But then I assumed you meant to pre-create the wanted types in a kind of registry and then ‘copy’ the wanted type from the registry. This seemed to work well. I hope I understood you correctly
With the second suggestion then it all just worked. Although I’m wondering if the switch / case statement would end up faster than the .MethodByName() function? I guess I can profile it to find out with differing numbers of switch cases?
Reflection will be slower than the switch/cases. Sorry about the ambiguity with newOf, but I think you got it now. To be clear, this is something like what I imagine doing:
It seems to work but has the disadvantage of pre-instantiating the types (slightly worse for memory?)? And then copying them could in theory be slower than creating them on demand? In short I like your clarified code with the functions better than my code