Type and Value
- 前言
- 一、reflect.Type
- 1.1 数据结构
- 1.2 方法
- 1.2.1 所有类型通用方法
- 1.2.2 不同基础类型的专有方法
- 二、reflect.Value
- 总结
- 参考资料
前言
reflect.Type和reflect.Value是go 反射的两大基本类型,一个管变量的类型方面,一个管变量的值方面。
一、reflect.Type
1.1 数据结构
reflect.Type是一个接口,定义了获取变量类型的相关信息的方法,rtype是其实现的结构体,通用的描述公共类型的结构。
type rtype struct {
size uintptr
ptrdata uintptr // number of bytes in the type that can contain pointers
hash uint32 // hash of type; avoids computation in hash tables
tflag tflag // extra type information flags
align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool
gcdata *byte // garbage collection data
str nameOff // string form
ptrToThis typeOff // type for pointer to this type, may be zero
}
可以通过func TypeOf(i interface{}) Type 来获取一个Type类型的接口变量。
为什么反射接口返回的是一个 Type 接口类型,而不是直接返回 Type ?
- 因为类型信息是一个只读的信息,不可能动态地修改类型的相关信息,那太不安全了;
- 因为不同的类型,类型定义也不一样,使用接口这一抽象数据结构能够进行统一的抽象。 所以refelct 包通过 reflect. TypeOf() 函数返回一个 Type 的接口变量,通过接口抽象出来的方法访问具体类型的信息。
1.2 方法
1.2.1 所有类型通用方法
// 所有类型通用的方法
type Type interface {
// 返回包含包名的类型名字,对于未命名类型返回的是空
Name() string
// Kind 返回该类型的底层基础类型
Kind() Kind
// 确定当前类型是否实现了 u 接口类型
// 注意这里的 u 必须是接口类型的 Type
Implements(u Type) bool
// 判断当前类型的实例是否能赋位给 type 为 u 的类型交量
AssignableTo(u Type) bool
// 判断当前类型的实例是否能强制类型转换为 u 类型交量
ConvertibleTo(u Type) bool
// 判断当前类型是否支持比较(等 于或不等于)
// 支持等于的类型可以作为 map 的 key
Comparable() bool
// 返回一个类型的方法的个数
NumMethod() int
// 通过索引位访问方法,索引值必须属于[ 0, NumMethod()],否则引发 panic
Method(int) Method
// 通过方法名获取 Method
MethodByName(string) (Method, bool)
// 返回类型的包路径,如采类型是预声明类型或未命名类型,则返回空字符串
PkgPath() string
// 返回存放该类型的实例需要多大的字节空间
Size() uintptr
}
1.2.2 不同基础类型的专有方法
这些方法是某种类型特有的 , 如果不是某种特定类型却调用了 该类型的方法, 则会引发panic 。所 以为了避免 panic , 在调用特定类型的专有方法前 ,要清楚地知道该类型是什么 ,如果不确定类型,则要先调用 kind() 方法确定类型后再调用类型的专有方法。
//Int*, Uint* , Float* , Complex* : Bits
//Array : Elem, Len
//Chan : ChanDir , Elem
//Func : In , NumIn , Out , NumOut , IsVariadic .
//Map : Key , Elem
//Ptr : Elem
//Slice : Elem
//Struct : Field, FieldByindex , FieldByName , FieldByNameFunc , NumField
// 返回类型的元素类型,该方法只适合 Array 、 Chan, Map, Ptr, Slice 类型
Elem() Type
// 返回数值型类型内存占用的位数
Bits() int
// struct 类型专用的方法
// 通过整数索 引获取 struct 字段
Field(i int) StructField
// /获取嵌入字段获取 struct 字段
FieldByIndex(index []int) StructField
// 通过名字查找获取 struct 字段
FieldByName(name string) (StructField, bool)
// func专用字段
// 返回第 i 个输入参数类型
In(i int) Type
// 返回第 i 个返回值类型
Out(i int) Type
// 输入参数个数
NumIn() int
// 返回值个数
NumOut() int
// map 类型专用的方法
// 返回map key 的 type
Key() Type
示例1:
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string "学生姓名" // tag
Age int `a:"1" b:"2"`
}
type Stu struct {
a *Stu
b int
}
func main() {
var stu Stu
fmt.Println(stu.a == nil, stu.b == 0)
rt := reflect.TypeOf(stu)
// FieldByName;Tag
if Name, ok := rt.FieldByName("Name"); ok {
fmt.Println(Name.Tag)
}
if Age, ok := rt.FieldByName("Age"); ok {
fmt.Println(Age.Tag.Get("a"))
fmt.Println(Age.Tag.Get("b"))
}
// rt本身的元信息
fmt.Println(rt.Name())
fmt.Println(rt.NumField())
fmt.Println(rt.PkgPath())
fmt.Println(rt.String())
// kind
fmt.Println(rt.Kind())
// 换种方式获取所有字段名称
for i := 0; i < rt.NumField(); i++ {
fmt.Printf("type.Field[%d].Name:%v \n", i, rt.Field(i).Name)
}
// slice
sc := make([]int, 10)
sc = append(sc, 1, 2, 3)
srt := reflect.TypeOf(sc)
// 元素的type
ert := srt.Elem()
fmt.Println(ert.Kind())
fmt.Printf("%d", ert.Kind())
fmt.Println(ert.NumMethod())
fmt.Println(ert.PkgPath())
}
示例2:
package main
import (
"fmt"
"reflect"
)
func main() {
// int 和 他名int 的当前类型和底层类型
var a Int = 1
var b int = 1
rta := reflect.TypeOf(a)
rtb := reflect.TypeOf(b)
fmt.Println(rta == rtb)
fmt.Println(rta.Kind() == rtb.Kind())
// 具体类型和接口类型的type
iA := new(A)
var sB A = B{}
var sC C
rtiA := reflect.TypeOf(iA)
rtsB := reflect.TypeOf(sB)
rtsC := reflect.TypeOf(sC)
//fmt.Println(reflect.TypeOf(rtiA.Field(1)))
fmt.Println(rtsB.Name())
fmt.Println(rtsC.Name())
fmt.Println(rtsB.Kind() == rtsC.Kind())
fmt.Println(rtiA.Kind())
}
type Int int
type A interface {
String() string
}
type B struct {
}
func (b B) String() string {
return "b"
}
type C struct {
}
二、reflect.Value
reflect.Value 表示实例的值信息, reflect.Value 是一个 struct ,并提供了一系列的 method 给使用者 。
type flag uintptr
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}
refelct. Value 总共有三个字段, 一个是值的类型指针 typ ,另 一个是指向值的指针 ptr , 最后一个是标记字段 flag 。
通过func ValueOf(i interface{}) Value 来获取变量Value的相关信息。
Value结构体提供了丰富的API给用户,简单的示例如下,
package main
import (
"fmt"
"reflect"
"unsafe"
)
type E interface {
e()
}
type F struct {
age int
}
func (f *F) e() {
}
func main() {
user := User{1, 18, "lls"}
u2 := user
u2.Id = 1
fmt.Println(&user == &u2)
uv := reflect.ValueOf(user)
uv2 := reflect.ValueOf(&user)
uv2.Elem().Field(0).Set(reflect.ValueOf(100))
fmt.Println(uv.CanSet(), uv.FieldByName("Id").CanSet())
uv2.Elem().Field(0).Set(reflect.ValueOf(100))
fmt.Println(uv2.CanSet(), uv2.Elem().Field(0).CanSet())
fmt.Println(uv2.Elem().Field(0), user.Id)
fmt.Println()
ut := reflect.TypeOf(user)
//reflect.PtrTo()
//a := reflect.New(ut)
a := reflect.NewAt(ut, unsafe.Pointer(&user))
fmt.Println(a, reflect.ValueOf(a))
fmt.Println(uv.Field(0))
for i := 0; i < uv.NumField(); i++ {
field := uv.Type().Field(i)
fieldValue := uv.Field(i).Interface()
switch val := fieldValue.(type) {
case int:
fmt.Println(field.Name, val, field.Type)
case string:
fmt.Println(field.Name, val, field.Type)
}
}
}
type User struct {
Id int
Age int
Name string
}
总结
1)reflect.Type是封装变量的类型相关信息,reflect.Value是封装变量的值信息。
参考资料
[1] Go 语言核心编程