我如何可以通过包名称列表中的所有结构和方法,或结构的名称来创建一个结构实例,如
package test
type User struct {
Name string
}
func getStructNameByPackageName(packageName string) []string{
...
}
func createStructInstance(structName string) interface{}{
...
}
调用函数getstructnamebypackagename(“test”)我们将得到结果:['User']
调用函数createstructinstance(“test.User”)我们将得到结果:一个用户实例
我在网上浏览了很多网页,但是大多数人说不能这么做。如果可以的话,请告诉我,非常感谢。
有疑问加站长微信联系(非本文作者)

没有这样的反射。建议你,如果有这样的需求,还不如使用类似 PHP 这样的动态语言
结构的名称来创建一个结构实例
我听着你是要做一个工厂模式?
看一下sql的驱动部分的实现吧,怎么从一个字符串来创建一个驱动的interface。
谢谢了,貌似行不通
调用函数createstructinstance(“test.User”)我们将得到结果:一个用户实例
这个必然行的通啊……
参考什么代码我都告诉你,你还想怎么样啊……
以我自己web工具库的某个缓存驱动的测试代码为例
https://github.com/herb-go/herb/blob/master/cache/drivers/freecache/freecache_test.go
而freecache只是我的驱动中的一种,我的驱动目前有6中
https://github.com/herb-go/herb/tree/master/cache/drivers
通过指定不同的字符串,比如 freecache,sqlcache,rediscache,redisluacache,hashcache,cachegroup。
可以创建不同的实例。
你要得就是这样的东西吧?
还有理论上,要做一个 func getStructNameByPackageName(packageName string) []string
也是很容易的事。
你需要的是做一个父级的包,做一个package级的变量,比如 Structs map[string][]string
getStructNameByPackageName 写在父包里面。
子包在func init() 里相关的信息和创建函数注册到父包里
@jarlyyn 我看到了那个源码,大致就是弄一个对象池,一个map,key是传入的字符串,v就是之前生成好的驱动,貌似没有用反射生成啊
@jarlyyn package级变量那个init()您的意思是不是我每增加一个struct就是init里面手动进行填入,例如: var structNames map[string][]string func init(){ structNames["test"] = append(structNames["test"],"User") structNames["test"] = append(structNames["test"],"Animal") structNames["test1"] = append(structNames["test"],"Ball") structNames["test1"] = append(structNames["test"],"Chair") } 之后获取的时候直接读取,每增加必须在init里面全部手动声明,或者把他写到一个配置文件里面yml,或者ini之后init方法读出来
你这个功能我说了啊,是工厂模式的需求啊,和反射没关系啊……
http://www.runoob.com/design-pattern/factory-pattern.html
以sql库为例
https://golang.org/pkg/database/sql/
有个全局的Drivers存放所有的driver信息
https://golang.org/src/database/sql/sql.go?s=1514:1537#L53
然后有一个Register方法,供子包把初始化函数以字符串的方式注册进模块
https://golang.org/src/database/sql/sql.go?s=1028:1076#L33
以mysql库为例
https://github.com/go-sql-driver/mysql/blob/master/driver.go
最后会在init方法里调用 sql.Register
写代码的时候,需要
import "database/sql" import _ "github.com/go-sql-driver/mysql"
db, err := sql.Open("mysql", "user:password@/dbname")
这样来使用
参考 https://github.com/go-sql-driver/mysql
这应该就是你需要的东西了吧?
@jarlyyn 这样其实也行,不过和我想要的有些区别, func init() { sql.Register("mysql", &MySQLDriver{}) } 这个其实就是手动的创建实例,我的本意是利用反射,只有给你个包名就会去动态搜寻下的所有类,去创建,这样不用手动创建了,类似于java的Class.forName("com.test.User").newInstance(),go里面提供了reflect.New(Type),type我没有发现能通过字符串生成的,这样说不知道你明白了吗,不过你给的对象池的那种也是一个办法,reflect.New不行的话,我打算就用你建议的那种了
这个不是对象池,这个是工厂的池,创建器的池……
比如我前面缓存的代码里,实现其实是靠下面这几块的。
factories = make(map[string]Factory)
type DriverConfig interface { Create() (Driver, error) }
type Factory func() DriverConfig
func Register(name string, f Factory) {
}
如果实在要用 reflect.New(Type),你直接把map里值设为 reflect.Type就行了。
但你如果用过golang反射包的话,golang是没有构建函数的,你 reflect.New(Type)是没用的,取到的是一个指向空的指针。还是需要自己的构建函数去构建的。