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?

1

2 Answers 2

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)
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

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.
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

9 Comments

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?
@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.
Reflection in general has a huge overhead, you're thinking in Python mentality right now, sit down and read golang.org/doc/effective_go.html.
@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.
@OneOfOne, Its cool. Half the time I write a comment it doesn't make any sense.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.