How to new an object with string in Golang

huangapple go评论80阅读模式
英文:

How to new an object with string in Golang

问题

在Golang中,你可以使用反射来根据类型的字符串创建对象。下面是一个示例代码:

import (
	"fmt"
	"reflect"
)

type someStruct struct {}

func main() {
	typeName := "someStruct"
	typeOfStruct := reflect.TypeOf(someStruct{})
	if typeOfStruct.Name() == typeName {
		resultObject := reflect.New(typeOfStruct).Elem().Interface()
		fmt.Printf("%T\n", resultObject)
	}
}

在上面的代码中,我们首先获取了类型的反射对象typeOfStruct,然后通过比较类型的名称和给定的类型字符串来判断是否匹配。如果匹配,我们使用reflect.New创建一个新的对象,并通过Elem()方法获取其指针所指向的值。最后,我们使用Interface()方法将结果对象转换为接口类型,以便进行后续操作。

请注意,使用反射可能会带来一些性能上的开销,因此在性能敏感的场景中需要谨慎使用。

英文:

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

得分: 7

不...

嗯,答案是“是的,但是”,这是一个很大的但是。在Go语言中,没有结构体名称的中央注册表。你不会得到一个名为StructFromName(string)的漂亮、干净的标准库函数,这可能是你希望得到的。

相反,你需要自己编写这个映射,类似于以下代码:

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 不是一个已知的结构体名称", name)
	}
}
英文:

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)
	}
}

答案2

得分: 6

在Go语言中,你不能直接通过类型名称来初始化一个类型实例。Go语言中与此最接近的是反射库中的reflect.New()函数,它接受一个reflect.Type对象并创建一个该类型的新值。

如果你想通过名称来初始化一个类型实例,你可以构建一个按名称注册类型的注册表,并编写一个函数通过名称查找类型并创建实例。虽然这种方法非常丑陋,而且不符合Go语言的惯用方式,但是它是可行的。

以下是一个可行的示例,你仍然需要手动进行类型转换:

package main

import (
	"fmt"
	"reflect"
)

// 一些结构体
type Foo struct {
	Lol string
}

type Bar struct {
	Wut string
}

// 类型注册表
var registry = map[string]reflect.Type{}

// 将类型添加到注册表
func registerType(t reflect.Type) {
	name := t.Name()
	registry[name] = t
}

// 根据名称创建新对象,并将其作为interface{}返回
func newByName(name string) interface{} {
	t, found := registry[name]
	if !found {
		panic("name not found!")
	}
	return reflect.New(t).Elem().Interface()
}

func main() {
	// 注册Foo和Bar类型
	registerType(reflect.TypeOf(Foo{}))
	registerType(reflect.TypeOf(Bar{}))

	// 创建新实例
	foo := newByName("Foo").(Foo)
	bar := newByName("Bar").(Bar)

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

再次强调,我不建议你这样做,这种方法既丑陋又慢,并且不符合Go语言的惯用方式。

英文:

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

huangapple
  • 本文由 发表于 2014年6月9日 16:37:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/24116522.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定