is there a way to create an instance of a struct from a string?
The Go runtime doesn't exposes a list of types built in the program. And there is a reason: you never have to be able to build all types availables but instead just a subset.
You can build yourself this subset using a map. And you can use the reflect
package to create an instance from a reflect.Type
.
My solution (see on Go Playground) uses typed nil pointers (instead of empty values) to reduce size of allocations when building the map (compared to @james-henstridge solution).
package main
import (
"fmt"
"reflect"
)
var typeRegistry = make(map[string]reflect.Type)
func registerType(typedNil interface{}) {
t := reflect.TypeOf(typedNil).Elem()
typeRegistry[t.PkgPath() + "." + t.Name()] = t
}
type MyString string
type myString string
func init() {
registerType((*MyString)(nil))
registerType((*myString)(nil))
// ...
}
func makeInstance(name string) interface{} {
return reflect.New(typeRegistry[name]).Elem().Interface()
}
func main() {
for k := range typeRegistry {
fmt.Println(k)
}
fmt.Printf("%T\n", makeInstance("main.MyString"))
fmt.Printf("%T\n", makeInstance("main.myString"))
}
There is no central registry of types in Go, so what you ask is impossible in the general case.
You could build up your own registry by hand to support such a feature using a map from strings to reflect.Type
values corresponding to each type. For instance:
var typeRegistry = make(map[string]reflect.Type)
func init() {
myTypes := []interface{}{MyString{}}
for _, v := range myTypes {
// typeRegistry["MyString"] = reflect.TypeOf(MyString{})
typeRegistry[fmt.Sprintf("%T", v)] = reflect.TypeOf(v)
}
}
You can then create instances of the types like so:
func makeInstance(name string) interface{} {
v := reflect.New(typeRegistry[name]).Elem()
// Maybe fill in fields here if necessary
return v.Interface()
}