英文:
Is it possible to store a Type in a map and use it later to instantiate an object in Go lang?
问题
我是新手学习Go语言,我遇到了一个问题。我需要创建一种“调度器”,它将接收一个字符串,并根据该字符串返回一个要实例化的类型。例如:
AnimalType := mymap["animal"]
newAnimal := new(AnimalType)
有没有一种方法可以实现这样的功能?
提前感谢。
英文:
I am new to Go and I have this problem. I need to make a kind of "dispatcher" that will receive a string and return a type to be instantiated based on the string. For example:
AnimalType := mymap["animal"]
newAnimal := new(AnimalType)
Is there a way to do so?
Thanks in advance.
答案1
得分: 2
你可以使用reflect
包来实现这个功能,不过需要注意的是,最终你还是需要知道具体的类型才能做更多的操作。
编辑:请注意,这本身是一个非常糟糕的想法,如果你正在这样做,你应该重新考虑。Go是一种静态类型语言,除非你真的需要使用reflect
包,否则尽量避免使用它。即使在大多数情况下,这已经为你处理好了。例如,JSON的编码/解码器。在其核心,它们使用了一些复杂的反射操作,但已经为你处理好了,直接使用即可。
需要注意的是,类型断言(.(*Thing1)
这些行)如果类型不匹配,会引发panic
。参考:https://tour.golang.org/methods/15
在playground上测试:https://play.golang.org/p/DhiTnCVJi1
package main
import (
"fmt"
"reflect"
)
type Thing1 bool
type Thing2 int
type Thing3 struct {
Item string
}
func main() {
m := map[string]reflect.Type{}
var t1 Thing1
var t2 Thing2
var t3 Thing3
m["thing1"] = reflect.TypeOf(t1)
m["thing2"] = reflect.TypeOf(t2)
m["thing3"] = reflect.TypeOf(t3)
// later on
// thing1
newT1Value := reflect.New(m["thing1"])
// you use * here because a pointer to a boolean type isn't useful
newT1 := *newT1Value.Interface().(*Thing1) // cast to concrete type
fmt.Printf("T1: %v\n", newT1)
// thing2
newT2Value := reflect.New(m["thing2"])
// you use * here because a pointer to an int type isn't useful
newT2 := *newT2Value.Interface().(*Thing2)
fmt.Printf("T2: %v\n", newT2)
// thing3
newT3Value := reflect.New(m["thing3"])
// you can choose to use * or not here. Pointers to structs are actually useful
newT3 := newT3Value.Interface().(*Thing3)
newT3.Item = "Hello world"
fmt.Printf("T3: %#v\n", newT3)
}
英文:
You can do this with the reflect
package, though it should be noted that eventually you have to know the concrete type to really do much with it.
EDIT: LET IT BE KNOWN. This is a very BAD idea in the first place, and if you are doing this, you should probably rethink things. Go is a statically typed language, and unless you REALLY need to use the reflect package, you should stay away from it if possible. Even then, in most cases, this has already been done for you. Take, for instance, the JSON Marshal/Unmarshaller. At its core, they do some nasty reflection stuff, but it is already taken care of for you, just use it.
It is important to note that the type assertions (the .(*Thing1)
lines) will panic
if it isn't the right type. See https://tour.golang.org/methods/15
Test on playground: https://play.golang.org/p/DhiTnCVJi1
package main
import (
"fmt"
"reflect"
)
type Thing1 bool
type Thing2 int
type Thing3 struct {
Item string
}
func main() {
m := map[string]reflect.Type{}
var t1 Thing1
var t2 Thing2
var t3 Thing3
m["thing1"] = reflect.TypeOf(t1)
m["thing2"] = reflect.TypeOf(t2)
m["thing3"] = reflect.TypeOf(t3)
// later on
// thing1
newT1Value := reflect.New(m["thing1"])
// you use * here because a pointer to a boolean type isn't useful
newT1 := *newT1Value.Interface().(*Thing1) // cast to concrete type
fmt.Printf("T1: %v\n", newT1)
// thing2
newT2Value := reflect.New(m["thing2"])
// you use * here because a pointer to an int type isn't useful
newT2 := *newT2Value.Interface().(*Thing2)
fmt.Printf("T2: %v\n", newT2)
// thing3
newT3Value := reflect.New(m["thing3"])
// you can choose to use * or not here. Pointers to structs are actually useful
newT3 := newT3Value.Interface().(*Thing3)
newT3.Item = "Hello world"
fmt.Printf("T3: %#v\n", newT3)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论