1

How can I create an object when I am only having its type in string? I am looking for something like:

type someStruct struct {}

resultObject := new "someStruct"

It will be really helpful and convenience with this when using different ORM library like GORP and GORM.

Is it possible to do it in Golang?

Anthony Tsang
  • 345
  • 1
  • 4
  • 13
  • 1
    possible duplicate of [is there a way to create an instance of a struct from a string?](http://stackoverflow.com/questions/23030884/is-there-a-way-to-create-an-instance-of-a-struct-from-a-string) – Linear Jun 09 '14 at 10:35

2 Answers2

7

No...

Well, the answer is "yes, but" and it's a big but. There's no central registry of struct names in Go. You're not going to get a nice, clean standard library function called StructFromName(string) which is probably what you were hoping for.

Instead, you have to write that mapping yourself, something like

func StringToStruct(name string) (interface{}, error) {
    switch name {
    case "SomeStruct":
        return SomeStruct{}, nil
    case "SomeOtherStruct":
        return SomeOtherStruct{}, nil
    case "subpackage.Struct":
        return subpackage.Struct{}, nil
    default:
        return nil, fmt.Errorf("%s is not a known struct name", name)
    }
}
Linear
  • 21,074
  • 4
  • 59
  • 70
  • Na...this kind of factory is not what I want. But still thx for answering. This solution maybe to final one if there is not better. – Anthony Tsang Jun 09 '14 at 09:39
6

You can't directly do that in Go. The only thing close to that Go supports is reflect.New() in the reflection library, which accepts a reflect.Type object and creates a new value of its type.

Now, if you'd like to initialize a type instance by name, you can build a registry of types by name, and have a function that looks up the type by name and creates an instance. It's really ugly though and not very idiomatic to Go, but it can be done.

[EDIT] here's a working example of this. You still need to do type conversion manually:

package main

import (
    "fmt"
    "reflect"
)

//just a couple of structs
type Foo struct {
    Lol string
}

type Bar struct {
    Wut string
}


//this is the registry of types by name
var registry = map[string]reflect.Type{}

// add a type to the registry
func registerType(t reflect.Type) {
    name := t.Name()
    registry[name] = t
}


// create a new object by name, returning it as interface{}
func newByName(name string) interface{} {

    t, found := registry[name]
    if !found {
        panic("name not found!")
    }

    return reflect.New(t).Elem().Interface()
}

func main() {

    //register foo and bar
    registerType(reflect.TypeOf(Foo{}))
    registerType(reflect.TypeOf(Bar{}))

    //create new instances
    foo := newByName("Foo").(Foo)
    bar := newByName("Bar").(Bar)

    fmt.Println(reflect.TypeOf(foo), reflect.TypeOf(bar))
}

And again, I wouldn't advise you to do this, it's ugly and slow and non idiomatic

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • Which part exactly you mean by slow? For me this is good enough to solve my case, really think you. I want to apply this keep of technique on ORM so that the objects will be more "related" and speed up the development. Or, is there a so-called "normal" way to duel with database entity? – Anthony Tsang Jun 09 '14 at 10:17
  • @AnthonyTsang just, you know, doing these dynamic things with strings, etc. It feels like Python, not Go :) It will work, but it's just no very go-ish, that's all. – Not_a_Golfer Jun 09 '14 at 11:26
  • 1
    Reflection in general has a huge overhead, you're thinking in Python mentality right now, sit down and read http://golang.org/doc/effective_go.html. – OneOfOne Jun 09 '14 at 13:06
  • 1
    @OneOfOne right, just worth noting that that that's how the json and xml libraries do this, more or less :) they use reflection to create instances, but they're not using a strinly typed registry. – Not_a_Golfer Jun 09 '14 at 13:17
  • This is a bit old but, @OneOfOne generally reflection in library code is acceptable, but in application code it is considered not considered idiomatic go – robbert229 Aug 23 '16 at 01:02
  • @robbert229 it's more complicated than that, there are things that you *have* to use reflection for, for example json/gob marshalling, but it doesn't change the fact it's a lot slower than not using it. Compare encoding/json to ffjson (which uses an external tool to generate structs) for example. – OneOfOne Aug 23 '16 at 21:39
  • @OneOfOne I completely agree. json/gob marshalling uses reflection heavily but in general it should be avoided. Hence why I said that the use of reflection in libraries is good, and in application code it is not... Rob Pike on reflection - It's a powerful tool that should be used with care and avoided unless strictly necessary. - https://blog.golang.org/laws-of-reflection – robbert229 Aug 24 '16 at 20:52
  • @robbert229 I misread what you said, I thought you were asking a question. – OneOfOne Aug 24 '16 at 21:02
  • 1
    @OneOfOne, Its cool. Half the time I write a comment it doesn't make any sense. – robbert229 Aug 24 '16 at 22:40