Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is there a way to create an instance of a struct from a string?

Tags:

go

Given a struct:

type MyStruct struct {     A int     B int } 

and a string with the struct's name

a := "MyStruct" 

or

a := "mypkg.MyStruct" 

How do I create an instance of my struct from the string name rather than the struct? The idea is that I would create an application with all of the structures linked into the binary but create the runtime instances from the strings. (sort of a meta-meta)

like image 328
Richard Avatar asked Apr 12 '14 13:04

Richard


People also ask

Can we create instance of structure?

A struct object can be created with or without the new operator, same as primitive type variables. Above, an object of the Coordinate structure is created using the new keyword.

Which is the correct way to create an instance of struct type?

Struct Instantiation Using new Keyword An instance of a struct can also be created with the new keyword. It is then possible to assign data values to the data fields using dot notation.

Can you put a string in a struct?

The answer is yes unless you are using an obsolete compiler that does not support initialization of structures with string class members. Make sure that the structure definition has access to the std namespace.

What is an instance of a struct called?

An instance of a class is traditionally known as an object. However, Swift structures and classes are much closer in functionality than in other languages, and much of this chapter describes functionality that applies to instances of either a class or a structure type.


2 Answers

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() } 
like image 152
James Henstridge Avatar answered Sep 18 '22 21:09

James Henstridge


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")) } 
like image 30
dolmen Avatar answered Sep 18 '22 21:09

dolmen