关于Go语言反射机制的浅谈

作者: 乘风御上者 分类: 综合 发布时间: 2022-05-23 15:28

刚把Go的基础语法过一遍,趁着知识还热乎,就想通过构思一个后台管理的框架,来巩固下所学技能。

在Github上扒拉了不少现有的的框架和项目,总觉得不太满意。其中最不能忍受的,就是不同包之间调用函数时,需要引入很多重复的包。

本来还是可以忍一下的,可刚有一个好的想法,却发现使用Go难以实现:

文件夹router目录下有若干个go文件,我希望后期用户可以随意增加或删除其中的go文件。
当然go文件的定义也有规定,文件内容是只定义一个函数(或结构体)且与文件名一致。

我的想法是: 当运行项目时,扫描router目录,得到每个go文件名,再通过反射执行里面的函数(或结构体的方法)。

因为router目录下的go文件名字是不确定的,按照Java或者PHP的方式是很容易实现的:

// Java方式
Class obj = Class.forName("完整.类名");
// PHP方式
$obj = new ReflectionClass("完整\类名");

然而我通过翻看反射相关的内容,发现居然,第一步“得到函数(或结构体)”是行不通的。

在Go反射相关的接口中并不能如此的获取函数或结构体。都说万事开头难,这完全是出师未捷身先死了!

我不死心的去发看了手头的书籍,又去查看了网上的许多博客,还去找了一些有工作经验的goer。无一例外的没把问题说在点上。

所有介绍go反射的文章或视频,都是建立在已经得到这个函数(或结构体)之上,然后可以剖析其中的属性或方法等等。

例如:

// 文章介绍通过字符串类型的函数名不能直接去调用函数
// 但是可以通过map方式婉转的实现该功能

func f1(){
	println("f1")
}

func main() {
	
	funcs := make(map[string]func())
	
	// 看到将f1赋值给map时,我是比较尴尬的。
	// 题目说只能得到字符串的“f1”, 后面的f1是外星人送的吗?
	funcs["f1"] = f1
	
	// 既然上面已经得到f1,这里完全不用这么费劲了,直接f1()
	funcs["f1"]()
}

又例如:

type Student struct {
	Name string
}

func (s Student) Info() {
	println("Student Info")
}

func main() {

	// 很明显,前提条件已经拿到结构体
	s := Student{}
	obj := reflect.ValueOf(s)
	
	// 通过字符串找方法是可行的
	infoFunc := obj.MethodByName("Info")

	infoFunc.Call([]reflect.Value{})
}

结构体的反射中通过字符串找方法是可以的,但其实还是第一步 [拿到结构体] 是办不到的。

折腾良久,问题依然没有很好的解决。

最终在Github上找到一个解决这类问题的项目,作者改写了底层逻辑,已经跳出了Go的功能接口。

或许是Go的静态编译机制导致的问题吧,总之Go的反射并不能算是完整反射。

哪位道友有解决之法,还望不吝赐教!

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表回复