14.手撕Go语言-反射
反射是指在运行时动态的访问和修改任意类型对象的结构和成员,在go语言中提供reflect包提供反射的功能,每一个变量都有两个属性:类型(Type)和值(Value)
Type
reflect.Type是一个接口类型,用于获取变量类型的信息,可通过reflect.TypeOf函数获取某个变量的类型信息
通用方法
-
Name(): 类型名
-
PkgPath(): 包路径
-
Kind(): 类型枚举值
-
String(): Type字符串
-
Comparable(): 是否可进行比较
-
Implements(Type): 是否实现某接口
-
AssignableTo(Type): 是否可赋值给某类型
-
ConvertibleTo(Type): 是否可转换为某类型
-
NumMethod(): 方法个数
-
Method(int): 通过索引获取方法类型
Method结构体常用属性:
- Name:方法名
- Type:函数类型
- Func:方法值(Value)
-
MethodByName(string): 通过方法名字获取方法类型
特定类型方法
-
reflect.Int, reflect.UInt,reflect.Float,reflect.Complex
- Bits(): 获取占用字节位数
-
reflact.Array
- Len(): 获取数组长度
- Elem(): 获取数据元素类型
-
reflect.Slice
- Elem(): 获取切片元素类型
-
reflect.Map
- Key(): 获取映射键类型
- Elem(): 获取映射值类型
-
reflect.Ptr
- Elem(): 获取指向值类型
-
reflect.Func
- IsVariadic(): 是否具有可变参数
- NumIn(): 参数个数
- In(int): 通过索引获取参数类型
- NumOut(): 返回值个数
- Out(int): 通过索引获取返回值类型
-
reflect.Struct
-
NumField(): 属性个数
-
Field(int):通过索引获取属性
StructField结构体常用属性:
-
Name:属性名
-
Anonymous:是否为匿名
-
Tag:标签
StructTag常用方法:
- Get(string)
- Lookup(string)
-
-
FieldByName(string): 通过属性名获取属性
-
Value
reflect.Value是一个结构体类型,用于获取变量值的信息,可通过reflect.ValueOf函数获取某个变量的值信息
通用方法
- Type(): 获取值类型
- CanAddr():是否可获取地址
- Addr(): 获取地址
- CanInterface(): 是否可以获取接口的
- InterfaceData():
- Interface(): 将变量转换为interface{}
- CanSet(): 是否可更新
- isValid(): 是否初始化为零值
- Kind():获取值类型枚举值
- NumMethod(): 方法个数
- Method(int): 通过索引获取方法值
- MethodByName(string): 通过方法名字获取方法值
- Convert(Type):转换为对应类型的值
修改方法
- Set/Set*:设置变量值
调用方法
- Call
- CallSlice
特定类型方法
-
reflect.Int, reflect.Uint,
- Int(): 获取对应类型值
- Unit():获取对应类型值
-
reflect.Float*
- Float():获取对应类型值
-
reflect.Complex*
- Complex():获取对应类型值
-
reflact.Array
- Len(): 获取数组长度
- Index(int): 根据索引获取元素
- Slice(int, int): 获取切片
- Slice3(int, int, int): 获取切片
-
reflect.Slice
- IsNil(): 判断是否为
- Len(): 获取元素数量
- Cap(): 获取容量
- Index(int): 根据索引获取元素
- Slice(int, int): 获取切片
- Slice3(int, int, int): 获取切片
-
reflect.Map
- IsNil(): 判断是否为
- Len(): 获取元素数量
- MapKeys(): 获取所有键
- MapIndex(Value): 根据键获取值
- MapRange():获取键值组成的可迭代对象
-
reflect.Ptr
- Elem(): 获取指向值类型(解引用)
-
reflect.Func
- IsVariadic(): 是否具有可变参数
- NumIn(): 参数个数
- In(int): 通过索引获取参数类型
- NumOut: 返回值个数
- Out(int): 通过索引获取返回值类型
-
reflect.Struct
-
NumField(): 属性个数
-
Field(int):通过索引获取属性
StructField结构体常用属性:
-
Name:属性名
-
Anonymous:是否为匿名
-
Tag:标签
StructTag常用方法:
- Get(string)
- Lookup(string)
-
FieldByName(string): 通过属性名获取属性
-
-
开发
objs包中创建用于测试的对象
14.01.png 14.02.png打印变量类型信息
14.03.png 14.04.png 14.05.png 14.06.png 14.07.png 14.08.png打印变量值信息
14.09.png 14.10.png 14.11.png 14.12.png对于包中的未公开属性可以通过反射获取到
更新变量值
14.13.png 14.14.png 14.15.png变量可修改的条件:
- 对于基本数据类型变量可获取地址
- 对于结构体属性必须是可获取地址且为公开的属性
调用函数
14.16.png 14.17.png 14.18.png动态创建结构体
14.19.png动态创建函数并调用
14.20.png 14.21.png应用
反射常用在动态处理所有数据类型(json/xml序列化和反序列化, orm等)或调用所有函数(路由函数调用)的场景
encoding/json
-
介绍
在内存数据进行持久化存储或网络交换时常可采用json格式字符串,go语言提供json包进行json序列化和反序列化
对于Go提供的基本类型和符合类型可以直接使用json包进行序列化和反序列化操作,针对结构体可通过标签声明属性和json字符串的转换关系,标签名为json,常用格式为:
-
json:
默认形式,可省略,json键名使用属性名,类型通过属性对应的类型
-
json:"key"
json键名使用指定名称key
-
json:"-"
忽略该属性
-
json:"key,type"
json键名使用指定名称key,类型使用指定类型type
-
json:"key,omitempty"
json键名使用指定名称key,当值为零值时省略该属性
-
json:"key,type,omitempty"
json键名使用指定名称key,类型使用指定类型type,当值为零值时省略该属性
-
json:",type"
类型使用指定类型type
-
json:",omitempty"
值为零值时省略该属性
-
-
数据初始化
14.23.png 14.24.png -
常用函数
-
Marshal: 用于将go语言的数据序列化为json字符串
-
Indent: 将json字符串进行格式化
14.25.png -
UnMarshal: 用于json字符串反序列化为go语言的数据
14.26.png -
MarshalIndent: 用于将go语言的数据序列化为格式化的json字符串
14.27.png -
Valid: 验证是否为正确json字符串
14.28.png
-
-
Encoder与Decoder
Encoder与Decoder是构建在流之上进行JSON序列化与反序列化,构造函数分别为NewEncoder和NewDecoder,参数要求分别实现接口io.Writer和io.Reader的对象
-
Encoder.Encode序列化
14.29.png -
Decoder.Decode反序列化
14.30.png
-
encoding/xml
-
介绍
go语言提供xml包进行xml序列化和反序列化
在进行xml序列化和反序列化时,必须定义根结构体对应xml的根节点,并可通过结构体中xml.Name类型且名称为XMLName属性来定义根节点,可通过各属性的标签声明属性和xml节点的转换关系,标签名为xml,常用格式为:
-
xml:
默认形式,可省略,xml节点使用结构体属性名
-
xml:"name"
xml节点名使用指定的名称name
-
xml:"-"
忽略该属性
-
xml:"name,attr"
表示该属性为节点的属性值,属性名使用指定名称name
-
xml:",attr"
表示为节点的属性值,属性名为结构体属性名
-
xml:"name,omitempty"
xml节点名使用指定的名称name,当值为零值时省略该属性
-
xml:",omitempty"
值为零值时省略该属性
-
xml:", chardata"
表示为文本
-
xml:",cdata"
表示使用CDATA包含
-
xml:",comment"
表示为注释内容
-
xml:", innerxml"
表示为数据不进行实体编码
-
xml:"A>B>C"
定义XML节点结构
-
-
数据初始化
14.32.png 14.33.png -
常用函数
-
Marshal: 用于将go语言的数据序列化为xml字符串
14.34.png -
UnMarshal: 用于xml字符串反序列化为go语言的数据
14.35.png -
MarshalIndent: 用于将go语言的数据序列化为格式化的xml字符串
14.36.png
-