Dynamically create variables of certain type based on string in Go

dynamic, go, interface, json, types

Solution

You can use reflection to get the zero value of, or to allocate a new value (like `new`) of a type using reflection, if you can get the `Type` value at runtime. However, I don't think there is a way to get the `Type` from a string. You would need to have a value of that type to get the type itself.

I adopted your idea, of using a map. I map the string to the type itself, which you can get using `reflect.TypeOf`, which gets the type out of an interface value. Then I used `reflect.Zero` to get the zero value of that type (a convenient value that exists for every type). Then I got the value out as an interface.

package main
import "reflect"

type ta struct { a int }
type tb struct { b float64 }
type tc struct { c string }

var mActions map[string]reflect.Type = make(map[string]reflect.Type)
func init() {
  var a ta
  mActions[`ta`] = reflect.TypeOf(a)
  var b tb
  mActions[`tb`] = reflect.TypeOf(b)
  var c ta
  mActions[`tc`] = reflect.TypeOf(c)
}

func MagicVarFunc(action string) interface{} {
  return reflect.Zero(mActions[action]).Interface()
}

func main() {
  t := "tb"
  v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
  x := v.(tb)
  x.b = 8.3
}

Problem

Simple version How can you create a variable of a certain type based upon the value of a string? ``` type ta struct { a int } type tb struct { b float } type tc struct { c string } t := "tb" v := MagicVarFunc(t) // Returns a new allocated var of type interface{} v.(tb).b = 8.3 ``` The true example In my, surprisingly enough, working example below, I am dynamically creating variables based on a string. This is done by registering each struct type in a map with the string being the key and a nil-pointer of the type being the value. Each type implements an interface with the method New() which returns a new variable of that specific type. The example below is very close to what I wish to do, where each action has a set of JSON encoded data which will populate the corresponding struct. The way I've structured it is also because I wish to be able to create new stand alone actions that I register to the map. I am not sure if am abusing the language now. May anyone give me any pointers if I am completely out of my mind? Is there an obviously easier way? ``` package main import ( "fmt" "encoding/json" ) // All I require of an action is that it may be executed type ActionHandler interface { Exec() New() ActionHandler } // My list of actions var mActions = make(map[string]ActionHandler) // Action Exit (leaving the program) type aExit struct {} func (s *aExit) Exec() { fmt.Println("Good bye") } func (s *aExit) New() ActionHandler { return new(aExit) } func init() { var a *aExit mActions[`exit`] = a } // Action Say (say a message to someone) type aSay struct { To string Msg string } func (s *aSay) Exec() { fmt.Println(`You say, "` + s.Msg + `" to ` + s.To) } func (s *aSay) New() ActionHandler { return new(aSay) } func init() { var a *aSay mActions[`say`] = a } func inHandler(action string, data []byte) { a := mActions[action].New() json.Unmarshal(data, &a) a.Exec() } func main(){ inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`)) inHandler(`exit`, []byte(`{}`)) } ```

Original source