go反射

itgeniusshuai · 2018-03-16 11:46:51 · 949 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-03-16 11:46:51 的主题,其中的信息可能已经有所发展或是发生改变。

我如何可以通过包名称列表中的所有结构和方法,或结构的名称来创建一个结构实例,如

package test
type User struct {
Name string
}
func getStructNameByPackageName(packageName string) []string{
...
}
func createStructInstance(structName string) interface{}{
...
}

调用函数getstructnamebypackagename(“test”)我们将得到结果:['User']

调用函数createstructinstance(“test.User”)我们将得到结果:一个用户实例

我在网上浏览了很多网页,但是大多数人说不能这么做。如果可以的话,请告诉我,非常感谢。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

949 次点击  
加入收藏 微博
11 回复  |  直到 2018-03-16 17:25:27
channel
channel · #1 · 7年之前

没有这样的反射。建议你,如果有这样的需求,还不如使用类似 PHP 这样的动态语言

jarlyyn
jarlyyn · #2 · 7年之前

结构的名称来创建一个结构实例

我听着你是要做一个工厂模式?

看一下sql的驱动部分的实现吧,怎么从一个字符串来创建一个驱动的interface。

itgeniusshuai
itgeniusshuai · #3 · 7年之前

谢谢了,貌似行不通

jarlyyn
jarlyyn · #4 · 7年之前
itgeniusshuaiitgeniusshuai #3 回复

谢谢了,貌似行不通

调用函数createstructinstance(“test.User”)我们将得到结果:一个用户实例

这个必然行的通啊……

参考什么代码我都告诉你,你还想怎么样啊……

jarlyyn
jarlyyn · #5 · 7年之前

以我自己web工具库的某个缓存驱动的测试代码为例

https://github.com/herb-go/herb/blob/master/cache/drivers/freecache/freecache_test.go

config := json.RawMessage("{\"Size\": 10000000}")
c := cache.New()
err := c.Init(cache.OptionJSON("freecache", config, ttl))

而freecache只是我的驱动中的一种,我的驱动目前有6中

https://github.com/herb-go/herb/tree/master/cache/drivers

通过指定不同的字符串,比如 freecache,sqlcache,rediscache,redisluacache,hashcache,cachegroup。

可以创建不同的实例。

你要得就是这样的东西吧?

jarlyyn
jarlyyn · #6 · 7年之前

还有理论上,要做一个 func getStructNameByPackageName(packageName string) []string

也是很容易的事。

你需要的是做一个父级的包,做一个package级的变量,比如 Structs map[string][]string

getStructNameByPackageName 写在父包里面。

子包在func init() 里相关的信息和创建函数注册到父包里

itgeniusshuai
itgeniusshuai · #7 · 7年之前

@jarlyyn 我看到了那个源码,大致就是弄一个对象池,一个map,key是传入的字符串,v就是之前生成好的驱动,貌似没有用反射生成啊

itgeniusshuai
itgeniusshuai · #8 · 7年之前

@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方法读出来

jarlyyn
jarlyyn · #9 · 7年之前
itgeniusshuaiitgeniusshuai #7 回复

@jarlyyn 我看到了那个源码,大致就是弄一个对象池,一个map,key是传入的字符串,v就是之前生成好的驱动,貌似没有用反射生成啊

你这个功能我说了啊,是工厂模式的需求啊,和反射没关系啊……

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

这应该就是你需要的东西了吧?

itgeniusshuai
itgeniusshuai · #10 · 7年之前

@jarlyyn 这样其实也行,不过和我想要的有些区别, func init() { sql.Register("mysql", &MySQLDriver{}) } 这个其实就是手动的创建实例,我的本意是利用反射,只有给你个包名就会去动态搜寻下的所有类,去创建,这样不用手动创建了,类似于java的Class.forName("com.test.User").newInstance(),go里面提供了reflect.New(Type),type我没有发现能通过字符串生成的,这样说不知道你明白了吗,不过你给的对象池的那种也是一个办法,reflect.New不行的话,我打算就用你建议的那种了

jarlyyn
jarlyyn · #11 · 7年之前
itgeniusshuaiitgeniusshuai #10 回复

@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)是没用的,取到的是一个指向空的指针。还是需要自己的构建函数去构建的。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传