【GO】一篇文章带你看透反射的原理

反射是什么

  • 对于运行时内存中的任何一个对象,你不须要预先知道其类型是什么,也能访问其所有属性,调用其所有方法;
  • 反射的主要做用在于编写通用的框架;
  • 用静态类型interface{}保存一个值,经过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值表明运行时的数据。Zero接受一个Type类型参数并返回一个表明该类型零值的Value类型值。

反射应用场景举例:导出商品列表到Excel

  • 需求是:无论用户在界面上看到什么商品,当它点击一下导出按钮,就将该商品的全部属性和值写出为文件;
  • 本例的难点是:咱们没法预知用户会选择导出什么类型的商品数据、它有哪些属性,也就没法相应地去建立Excel数据表的列;
  • 由于商品的种类太多,若是用“正射”去作,那么有多少商品类型咱们就要写多少个switch或if分支,而后在每个分支里根据当前分支的具体商品类型去构造相应的数据列,这显然是狠蹩脚、狠难维护和扩展的;
  • 而经过反射来作就易如反掌了,管你用户要导出的是什么商品实例,我能够动态地解析其类型、动态获知其全部属性和方法,而后根据再根据其具体属性名称去建立相应的表格列,并将属性值填入其中;

而后咱们开始看案例

首先须要定义俩个结构体

而且People继承PeopleParent微信

package main

import (
	"fmt"
	"reflect"
)

type PeopleParent struct { 
	Kaka string
}

type People struct { 
	PeopleParent
	Name string
	Age  int
}

定义一个方法为了在使用value接口演示使用

func (p People) Eat(name string) { 
	fmt.Println("咔咔在吃什么呢!", name)
	p.Name = name
}

在main函数里边咱们把People结构体的对象给建立出来

建立了机构对象而且复制给P 而且调用了typeAPI方法,把p传入进去框架

func main() { 
	p := People{ 
		PeopleParent: PeopleParent{ Kaka: "咔咔的父类属性"},
		Name:         "咔咔",
		Age:          24,
	}
	typeAPI(p)
	valueAPI(p)
}

开始咱们的typeAPI的一些接口

func typeAPI(obj interface{ }) { 
	// 返回保存值的类型
	oType := reflect.TypeOf(obj)
	fmt.Println(oType) // main.People
	// 原始类型
	kind := oType.Kind()
	fmt.Println(kind) // struct
	// 类型名称
	fmt.Println(oType.Name()) // People
	// 属性和方法的个数
	fmt.Println(oType.NumField())  // 2
	fmt.Println(oType.NumMethod()) // 0
	// 获取所有属性
	for i := 0; i < oType.NumField(); i++ { 
		structField := oType.Field(i)
		// name string age int
		fmt.Println(structField.Name, structField.Type)
	}
	// 获取所有方法
	for i := 0; i < oType.NumMethod(); i++ { 
		structMethod := oType.Method(i)
		fmt.Println(structMethod.Name, structMethod.Type)
	}
	// 获取父类的属性 []int{0, 0}获取第0个父类 第0个属性
	fmt.Println(oType.FieldByIndex([]int{ 0, 0}).Name)
}

value的一些接口

在这里咱们须要注意的是方法传入的是结构体的值并不是指针函数

在修改属性值时是传的指针,这点看清楚spa

咱们看到的是elem也能够调用结构体的方法指针

咱们代码的一开始是ValueOf§ 若是改成*p也是跟elem同样的code

valueOf := reflect.ValueOf(&p)
	byEat := valueOf.MethodByName("Eat")
	byEat.Call([]reflect.Value{ reflect.ValueOf("西瓜")})
	fmt.Println(valueOf)
func valueAPI(p People) { 
	valueOf := reflect.ValueOf(p)
	// 获取全部属性值
	for i := 0; i < valueOf.NumField(); i++ { 
		value := valueOf.Field(i)
		// {}
		//咔咔
		//24
		fmt.Println(value)
	}
	// 获取父类属性
	fieldByIndex := valueOf.FieldByIndex([]int{ 0, 0})
	fmt.Println(fieldByIndex.Interface()) // 咔咔的父类属性

	// 得到指针value的内容进而得到成员的值
	valuePrt := reflect.ValueOf(&p)
	elem := valuePrt.Elem()
	value := elem.Field(0).Interface()
	fmt.Println(value) //{咔咔的父类属性}

	// 根据属性名获取值
	age := elem.FieldByName("Age")
	fmt.Println("咔咔的年龄", age) // 咔咔的年龄 24
	// 修改属性值
	elem.FieldByName("Age").SetInt(26)
	fmt.Println(elem) //{ {咔咔的父类属性} 咔咔 26}

	// 调用对象的方法
	mValue := elem.MethodByName("Eat")
	// 参数须要反射
	mValue.Call([]reflect.Value{ reflect.ValueOf("西瓜")})
	fmt.Println(elem) //咔咔在吃什么呢! 西瓜
}

完整代码

package main

import (
	"fmt"
	"reflect"
)

type PeopleParent struct { 
	Kaka string
}

type People struct { 
	PeopleParent
	Name string
	Age  int
}

func (p People) Eat(name string) { 
	fmt.Println("咔咔在吃什么呢!", name)
	p.Name = name
}

func main() { 
	p := People{ 
		PeopleParent: PeopleParent{ Kaka: "咔咔的父类属性"},
		Name:         "咔咔",
		Age:          24,
	}
	typeAPI(p)
	valueAPI(p)
}
func typeAPI(obj interface{ }) { 
	// 返回保存值的类型
	oType := reflect.TypeOf(obj)
	fmt.Println(oType) // main.People
	// 原始类型
	kind := oType.Kind()
	fmt.Println(kind) // struct
	// 类型名称
	fmt.Println(oType.Name()) // People
	// 属性和方法的个数
	fmt.Println(oType.NumField())  // 2
	fmt.Println(oType.NumMethod()) // 0
	// 获取所有属性
	for i := 0; i < oType.NumField(); i++ { 
		structField := oType.Field(i)
		// name string age int
		fmt.Println(structField.Name, structField.Type)
	}
	// 获取所有方法
	for i := 0; i < oType.NumMethod(); i++ { 
		structMethod := oType.Method(i)
		fmt.Println(structMethod.Name, structMethod.Type)
	}
	// 获取父类的属性 []int{0, 0}获取第0个父类 第0个属性
	fmt.Println(oType.FieldByIndex([]int{ 0, 0}).Name)
}

func valueAPI(p People) { 
	valueOf := reflect.ValueOf(p)
	//valueOf := reflect.ValueOf(&p)
	//byEat := valueOf.MethodByName("Eat")
	//byEat.Call([]reflect.Value{reflect.ValueOf("西瓜")})
	//fmt.Println(valueOf)
	// 获取全部属性值
	for i := 0; i < valueOf.NumField(); i++ { 
		value := valueOf.Field(i)
		// {}
		//咔咔
		//24
		fmt.Println(value)
	}
	// 获取父类属性
	fieldByIndex := valueOf.FieldByIndex([]int{ 0, 0})
	fmt.Println(fieldByIndex.Interface()) // 咔咔的父类属性

	// 得到指针value的内容进而得到成员的值
	valuePrt := reflect.ValueOf(&p)
	elem := valuePrt.Elem()
	value := elem.Field(0).Interface()
	fmt.Println(value) //{咔咔的父类属性}

	// 根据属性名获取值
	age := elem.FieldByName("Age")
	fmt.Println("咔咔的年龄", age) // 咔咔的年龄 24
	// 修改属性值
	elem.FieldByName("Age").SetInt(26)
	fmt.Println(elem) //{ {咔咔的父类属性} 咔咔 26}

	// 调用对象的方法
	mValue := elem.MethodByName("Eat")
	// 参数须要反射
	mValue.Call([]reflect.Value{ reflect.ValueOf("西瓜")})
	fmt.Println(elem) //咔咔在吃什么呢! 西瓜
}

博主微信欢迎交流

在这里插入图片描述

相关文章
相关标签/搜索