在Go语言中,是否可以将类型存储在map中,并在以后使用它来实例化对象?

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

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

huangapple
  • 本文由 发表于 2017年3月31日 01:18:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/43124427.html
匿名

发表评论

匿名网友

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

确定