英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论