设为首页 收藏本站
查看: 1368|回复: 0

[经验分享] Golang学习 - reflect 包

[复制链接]

尚未签到

发表于 2018-9-19 12:09:57 | 显示全部楼层 |阅读模式
------------------------------------------------------------  

  
  在 reflect 包中,主要通过两个函数 TypeOf() 和 ValueOf() 实现反射,TypeOf() 获取到的结果是 reflect.Type 类型,ValueOf() 获取到的结果是 reflect.Value 类型,这两种类型都有很多方法可以进一步获取相关的反射信息。
  

  
  这里有一个函数,可以获取指定对象的所有字段和方法:
  

  
------------------------------
  

  
// 获取一个对象的字段和方法
  
package main
  

  
import (
  
"fmt"
  
"reflect"
  
)
  

  
// 获取一个对象的字段和方法
  
func GetMembers(i interface{}) {
  
// 获取 i 的类型信息
  
t := reflect.TypeOf(i)
  

  
for {
  
// 进一步获取 i 的类别信息
  
if t.Kind() == reflect.Struct {
  
// 只有结构体可以获取其字段信息
  
fmt.Printf("\n%-8v %v 个字段:\n", t, t.NumField())
  
// 进一步获取 i 的字段信息
  
for i := 0; i < t.NumField(); i++ {
  
fmt.Println(t.Field(i).Name)
  
}
  
}
  
// 任何类型都可以获取其方法信息
  
fmt.Printf("\n%-8v %v 个方法:\n", t, t.NumMethod())
  
// 进一步获取 i 的方法信息
  
for i := 0; i < t.NumMethod(); i++ {
  
fmt.Println(t.Method(i).Name)
  
}
  
if t.Kind() == reflect.Ptr {
  
// 如果是指针,则获取其所指向的元素
  
t = t.Elem()
  
} else {
  
// 否则上面已经处理过了,直接退出循环
  
break
  
}
  
}
  
}
  

  
// 定义一个结构体用来进行测试
  
type sr struct {
  
string
  
}
  

  
// 接收器为实际类型
  
func (s sr) Read() {
  
}
  

  
// 接收器为指针类型
  
func (s *sr) Write() {
  
}
  

  
func main() {
  
// 测试
  
GetMembers(&sr{})
  
}
  

  
/* 测试结果(可以读取私有字段):
  
*main.sr 2 个方法:
  
Read
  
Write
  

  
main.sr  1 个字段:
  
string
  

  
main.sr  1 个方法:
  
Read
  
*/
  

  
------------------------------
  

  
  我们可以通过下面的代码获取 reflect.Type 的所有方法,以便进行学习:
  

  
// reflect.Type 是一个接口类型
  
GetMembers(new(reflect.Type))
  

  
  列出的方法并不一定通用,需要根据不同的类型选择使用,我们在这里给它们分一下类:
  

  
------------------------------
  

  
// 通用
  

  
// 获取 t 类型的字符串描述,不要通过 String 来判断两种类型是否一致。
  
func (t *rtype) String() string
  

  
// 获取 t 类型在其包中定义的名称,未命名类型则返回空字符串。
  
func (t *rtype) Name() string
  

  
// 获取 t 类型所在包的名称,未命名类型则返回空字符串。
  
func (t *rtype) PkgPath() string
  

  
// 获取 t 类型的类别。
  
func (t *rtype) Kind() reflect.Kind
  

  
// 获取 t 类型的值在分配内存时的大小,功能和 unsafe.SizeOf 一样。

  
func (t *rtype)>  

  
// 获取 t 类型的值在分配内存时的字节对齐值。
  
func (t *rtype) Align() int
  

  
// 获取 t 类型的值作为结构体字段时的字节对齐值。
  
func (t *rtype) FieldAlign() int
  

  
// 获取 t 类型的方法数量。
  
func (t *rtype) NumMethod() int
  

  
// 根据索引获取 t 类型的方法,如果方法不存在,则 panic。
  
// 如果 t 是一个实际的类型,则返回值的 Type 和 Func 字段会列出接收者。
  
// 如果 t 只是一个接口,则返回值的 Type 不列出接收者,Func 为空值。
  
func (t *rtype) Method() reflect.Method
  

  
// 根据名称获取 t 类型的方法。
  
func (t *rtype) MethodByName(string) (reflect.Method, bool)
  

  
// 判断 t 类型是否实现了 u 接口。
  
func (t *rtype) Implements(u reflect.Type) bool
  

  
// 判断 t 类型的值可否转换为 u 类型。
  
func (t *rtype) ConvertibleTo(u reflect.Type) bool
  

  
// 判断 t 类型的值可否赋值给 u 类型。
  
func (t *rtype) AssignableTo(u reflect.Type) bool
  

  
// 判断 t 类型的值可否进行比较操作
  
func (t *rtype) Comparable() bool
  

  
------------------------------
  

  
// 示例
  
type inf interface {
  
Method1()
  
Method2()
  
}
  

  
type ss struct {
  
a func()
  
}
  

  
func (i ss) Method1() {}
  
func (i ss) Method2() {}
  

  
func main() {
  
s := reflect.TypeOf(ss{})
  
i := reflect.TypeOf(new(inf)).Elem()
  

  
Test(s)
  
Test(i)
  
}
  

  
func Test(t reflect.Type) {
  
if t.NumMethod() > 0 {
  
fmt.Printf("\n--- %s ---\n", t)
  
fmt.Println(t.Method(0).Type)
  
fmt.Println(t.Method(0).Func.String())
  
}
  
}
  

  
// 输出结果:
  
// --- main.ss ---
  
// func(main.ss)
  
//
  
//
  
// --- main.inf ---
  
// func()
  
//
  

  
------------------------------
  

  
// 数值
  

  
// 获取数值类型的位宽,t 必须是整型、浮点型、复数型
  
func (t *rtype) Bits() int
  

  
------------------------------
  

  
// 数组
  

  
// 获取数组的元素个数
  
func (t *rtype) Len() int
  

  
------------------------------
  

  
// 映射
  

  
// 获取映射的键类型
  
func (t *rtype) Key() reflect.Type
  

  
------------------------------
  

  
// 通道
  

  
// 获取通道的方向
  
func (t *rtype) ChanDir() reflect.ChanDir
  

  
------------------------------
  

  
// 结构体
  

  
// 获取字段数量
  
func (t *rtype) NumField() int
  

  
// 根据索引获取字段
  
func (t *rtype) Field(int) reflect.StructField
  

  
// 根据名称获取字段
  
func (t *rtype) FieldByName(string) (reflect.StructField, bool)
  

  
// 根据指定的匹配函数 math 获取字段
  
func (t *rtype) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool)
  

  
// 根据索引链获取嵌套字段
  
func (t *rtype) FieldByIndex(index []int) reflect.StructField
  

  
------------------------------
  

  
// 函数
  

  
// 获取函数的参数数量
  
func (t *rtype) NumIn() int
  

  
// 根据索引获取函数的参数信息
  
func (t *rtype) In(int) reflect.Type
  

  
// 获取函数的返回值数量
  
func (t *rtype) NumOut() int
  

  
// 根据索引获取函数的返回值信息
  
func (t *rtype) Out(int) reflect.Type
  

  
// 判断函数是否具有可变参数。
  
// 如果有可变参数,则 t.In(t.NumIn()-1) 将返回一个切片。
  
func (t *rtype) IsVariadic() bool
  

  
------------------------------
  

  
// 数组、切片、映射、通道、指针、接口
  

  
// 获取元素类型、获取指针所指对象类型,获取接口的动态类型
  
func (t *rtype) Elem() reflect.Type
  

  
------------------------------
  

  
  下面的代码用到了所有这些方法:
  

  
------------------------------
  

  
// 获取各种类型的相关信息
  
package main
  

  
import (
  
"fmt"
  
"reflect"
  
"unsafe"
  
)
  

  
// 嵌套结构体
  
type ss struct {
  
a struct {
  
int
  
string
  
}
  
int
  
string
  
bool
  
float64
  
}
  

  
func (s ss) Method1(i int) string  { return "结构体方法1" }
  
func (s *ss) Method2(i int) string { return "结构体方法2" }
  

  
var (
  
intValue   = int(0)
  
int8Value  = int8(8)
  
int16Value = int16(16)
  
int32Value = int32(32)
  
int64Value = int64(64)
  

  
uIntValue   = uint(0)
  
uInt8Value  = uint8(8)
  
uInt16Value = uint16(16)
  
uInt32Value = uint32(32)
  
uInt64Value = uint64(64)
  

  
byteValue    = byte(0)
  
runeValue    = rune(0)
  
uintptrValue = uintptr(0)
  

  
boolValue   = false
  
stringValue = ""
  

  
float32Value = float32(32)
  
float64Value = float64(64)
  

  
complex64Value  = complex64(64)
  
complex128Value = complex128(128)
  

  
arrayValue  = [5]string{}           // 数组
  
sliceValue  = []byte{0, 0, 0, 0, 0} // 切片
  
mapValue    = map[string]int{}      // 映射
  
chanValue   = make(chan int, 2)     // 通道
  
structValue = ss{                   // 结构体
  
struct {
  
int
  
string
  
}{10, "子结构体"},
  
20,
  
"结构体",
  
false,
  
64.0,
  
}
  

  
func1Value = func(a, b, c int) string { // 函数(固定参数)
  
return fmt.Sprintf("固定参数:%v %v %v", a, b, c)
  
}
  

  
func2Value = func(a, b int, c ...int) string { // 函数(动态参数)
  
return fmt.Sprintf("动态参数:%v %v %v", a, b, c)
  
}
  

  
unsafePointer     = unsafe.Pointer(&structValue)    // 通用指针
  
reflectType       = reflect.TypeOf(0)               // 反射类型
  
reflectValue      = reflect.ValueOf(0)              // 反射值
  
reflectArrayValue = reflect.ValueOf([]int{1, 2, 3}) // 切片反射值
  
// 反射接口类型
  
interfaceType = reflect.TypeOf(new(interface{})).Elem()
  
)
  

  
// 简单类型
  
var simpleTypes = []interface{}{
  
intValue, &intValue, // int
  
int8Value, &int8Value, // int8
  
int16Value, &int16Value, // int16
  
int32Value, &int32Value, // int32
  
int64Value, &int64Value, // int64
  
uIntValue, &uIntValue, // uint
  
uInt8Value, &uInt8Value, // uint8
  
uInt16Value, &uInt16Value, // uint16
  
uInt32Value, &uInt32Value, // uint32
  
uInt64Value, &uInt64Value, // uint64
  
byteValue, &byteValue, // byte
  
runeValue, &runeValue, // rune
  
uintptrValue, &uintptrValue, // uintptr
  
boolValue, &boolValue, // bool
  
stringValue, &stringValue, // string
  
float32Value, &float32Value, // float32
  
float64Value, &float64Value, // float64
  
complex64Value, &complex64Value, // complex64
  
complex128Value, &complex128Value, // complex128
  
}
  

  
// 复杂类型
  
var complexTypes = []interface{}{
  
arrayValue, &arrayValue, // 数组
  
sliceValue, &sliceValue, // 切片
  
mapValue, &mapValue, // 映射
  
chanValue, &chanValue, // 通道
  
structValue, &structValue, // 结构体
  
func1Value, &func1Value, // 定参函数
  
func2Value, &func2Value, // 动参函数
  
structValue.Method1, structValue.Method2, // 方法
  
unsafePointer, &unsafePointer, // 指针
  
reflectType, &reflectType, // 反射类型
  
reflectValue, &reflectValue, // 反射值
  
interfaceType, &interfaceType, // 接口反射类型
  
}
  

  
// 空值
  
var unsafeP unsafe.Pointer
  

  
// 空接口
  
var nilInterfece interface{}
  

  
func main() {
  
// 测试简单类型
  
for i := 0; i < len(simpleTypes); i++ {
  
PrintInfo(simpleTypes)
  
}
  
// 测试复杂类型
  
for i := 0; i < len(complexTypes); i++ {
  
PrintInfo(complexTypes)
  
}
  
// 测试单个对象
  
PrintInfo(unsafeP)
  
PrintInfo(&unsafeP)
  
PrintInfo(nilInterfece)
  
PrintInfo(&nilInterfece)
  
}
  

  
func PrintInfo(i interface{}) {
  
if i == nil {
  
fmt.Println("--------------------")
  
fmt.Printf("无效接口值:%v\n", i)
  
return
  
}
  
t := reflect.TypeOf(i)
  
PrintType(t)
  
}
  

  
func PrintType(t reflect.Type) {
  
fmt.Println("--------------------")
  
// ----- 通用方法 -----
  
fmt.Println("String             :", t.String())     // 类型字符串
  
fmt.Println("Name               :", t.Name())       // 类型名称
  
fmt.Println("PkgPath            :", t.PkgPath())    // 所在包名称
  
fmt.Println("Kind               :", t.Kind())       // 所属分类
  
fmt.Println("Size               :", t.Size())       // 内存大小
  
fmt.Println("Align              :", t.Align())      // 字节对齐
  
fmt.Println("FieldAlign         :", t.FieldAlign()) // 字段对齐
  
fmt.Println("NumMethod          :", t.NumMethod())  // 方法数量
  
if t.NumMethod() > 0 {
  
i := 0
  
for ; i < t.NumMethod()-1; i++ {
  
fmt.Println("    ┣", t.Method(i).Name) // 通过索引定位方法
  
}
  
fmt.Println("    ┗", t.Method(i).Name) // 通过索引定位方法
  
}
  
if sm, ok := t.MethodByName("String"); ok { // 通过名称定位方法
  
fmt.Println("MethodByName       :", sm.Index, sm.Name)
  
}
  
fmt.Println("Implements(i{})    :", t.Implements(interfaceType))  // 是否实现了指定接口
  
fmt.Println("ConvertibleTo(int) :", t.ConvertibleTo(reflectType)) // 是否可转换为指定类型
  
fmt.Println("AssignableTo(int)  :", t.AssignableTo(reflectType))  // 是否可赋值给指定类型的变量
  
fmt.Println("Comparable         :", t.Comparable())               // 是否可进行比较操作
  
// ----- 特殊类型 -----
  
switch t.Kind() {
  
// 指针型:
  
case reflect.Ptr:
  
fmt.Println("=== 指针型 ===")
  
// 获取指针所指对象
  
t = t.Elem()
  
fmt.Printf("转换到指针所指对象 : %v\n", t.String())
  
// 递归处理指针所指对象
  
PrintType(t)
  
return
  
// 自由指针型:
  
case reflect.UnsafePointer:
  
fmt.Println("=== 自由指针 ===")
  
// ...
  
// 接口型:
  
case reflect.Interface:
  
fmt.Println("=== 接口型 ===")
  
// ...
  
}
  
// ----- 简单类型 -----
  
// 数值型:
  
if reflect.Int  0 {
  
for j = 0; j < field.Type.NumField()-1; j++ {
  
subfield := t.FieldByIndex([]int{i, j}) // 获取嵌套结构体字段
  
fmt.Printf("    │    ├ %v\n", subfield.Name)
  
}
  
subfield := t.FieldByIndex([]int{i, j}) // 获取嵌套结构体字段
  
fmt.Printf("    │    └ %%v\n", subfield.Name)
  
}
  
}
  
field := t.Field(i) // 获取结构体字段
  
fmt.Printf("    └ %v\n", field.Name)
  
// 通过名称查找字段
  
if field, ok := t.FieldByName("ptr"); ok {
  
fmt.Println("FieldByName(ptr)   :", field.Name)
  
}
  
// 通过函数查找字段
  
if field, ok := t.FieldByNameFunc(func(s string) bool { return len(s) > 3 }); ok {
  
fmt.Println("FieldByNameFunc    :", field.Name)
  
}
  
}
  
// 函数型:
  
case reflect.Func:
  
fmt.Println("=== 函数型 ===")
  
fmt.Println("IsVariadic         :", t.IsVariadic()) // 是否具有变长参数
  
fmt.Println("NumIn              :", t.NumIn())      // 参数数量
  
if t.NumIn() > 0 {
  
i := 0
  
for ; i < t.NumIn()-1; i++ {
  
fmt.Println("    ┣", t.In(i)) // 获取参数类型
  
}
  
fmt.Println("    ┗", t.In(i)) // 获取参数类型
  
}
  
fmt.Println("NumOut             :", t.NumOut()) // 返回值数量
  
if t.NumOut() > 0 {
  
i := 0
  
for ; i < t.NumOut()-1; i++ {
  
fmt.Println("    ┣", t.Out(i)) // 获取返回值类型
  
}
  
fmt.Println("    ┗", t.Out(i)) // 获取返回值类型
  
}
  
}
  
}
  

  
------------------------------------------------------------
  

  
  接下来学习 reflect.Value 的所有方法,还是进行分类学习,这里的很多操作(比如取地址、取切片、修改映射、通道进出、取值、赋值、函数调用等)和平时的操作都一样,只不过在这里需要用各种方法来操作,而平时只需要用一些符号来操作。
  

  
  注意:下面描述的 v 值是指 reflect.Value 所代表的实际值,而不是 reflect.Value 本身。
  

  
------------------------------
  

  
// 特殊
  

  
// 判断 v 值是否可寻址
  
// 1、指针的 Elem() 可寻址
  
// 2、切片的元素可寻址
  
// 3、可寻址数组的元素可寻址
  
// 4、可寻址结构体的字段可寻址,方法不可寻址
  
// 也就是说,如果 v 值是指向数组的指针“&数组”,通过 v.Elem() 获取该指针指向的数组,那么
  
// 该数组就是可寻址的,同时该数组的元素也是可寻址的,如果 v 就是一个普通数组,不是通过解引
  
// 用得到的数组,那么该数组就不可寻址,其元素也不可寻址。结构体亦然。
  
func (v Value) CanAddr() bool
  

  
// 获取 v 值的地址,相当于 & 取地址操作。v 值必须可寻址。
  
func (v Value) Addr() reflect.Value
  

  
// 判断 v 值是否可以被修改。只有可寻址的 v 值可被修改。
  
// 结构体中的非导出字段(通过 Field() 等方法获取的)不能修改,所有方法不能修改。
  
func (v Value) CanSet() bool
  

  
// 判断 v 值是否可以转换为接口类型
  
// 结构体中的非导出字段(通过 Field() 等方法获取的)不能转换为接口类型
  
func (v Value) CanInterface() bool
  

  
// 将 v 值转换为空接口类型。v 值必须可转换为接口类型。
  
func (v Value) Interface() interface{}
  

  
// 使用一对 uintptr 返回接口的数据
  
func (v Value) InterfaceData() [2]uintptr
  

  
------------------------------
  

  
// 示例:
  
type ss struct {
  
A int
  
a int
  
}
  

  
func (s ss) Method1(i int) string  { return "结构体方法1" }
  
func (s *ss) Method2(i int) string { return "结构体方法2" }
  

  
func main() {
  
v1 := reflect.ValueOf(ss{})                   // 结构体
  
v2 := reflect.ValueOf(&ss{})                  // 结构体指针
  
v3 := reflect.ValueOf(&ss{}).Elem()           // 可寻址结构体
  
v4 := reflect.ValueOf(&ss{}).Elem().Field(0)  // 可寻址结构体的共有字段
  
v5 := reflect.ValueOf(&ss{}).Elem().Field(1)  // 可寻址结构体的私有字段
  
v6 := reflect.ValueOf(&ss{}).Method(0)        // 结构体指针的方法
  
v7 := reflect.ValueOf(&ss{}).Elem().Method(0) // 结构体的方法
  

  
fmt.Println(v1.CanAddr()) // false
  
fmt.Println(v2.CanAddr()) // false
  
fmt.Println(v3.CanAddr()) // true
  
fmt.Println(v4.CanAddr()) // true
  
fmt.Println(v5.CanAddr()) // true
  
fmt.Println(v6.CanAddr()) // false
  
fmt.Println(v7.CanAddr()) // false
  
fmt.Println("----------")
  
fmt.Println(v1.CanSet()) // false
  
fmt.Println(v2.CanSet()) // false
  
fmt.Println(v3.CanSet()) // true
  
fmt.Println(v4.CanSet()) // true
  
fmt.Println(v5.CanSet()) // false
  
fmt.Println(v6.CanSet()) // false
  
fmt.Println(v6.CanSet()) // false
  
fmt.Println("----------")
  
fmt.Println(v1.CanInterface()) // true
  
fmt.Println(v2.CanInterface()) // true
  
fmt.Println(v3.CanInterface()) // true
  
fmt.Println(v4.CanInterface()) // true
  
fmt.Println(v5.CanInterface()) // false
  
fmt.Println(v6.CanInterface()) // true
  
fmt.Println(v7.CanInterface()) // true
  
}
  

  
------------------------------
  

  
// 指针
  

  
// 将 v 值转换为 uintptr 类型,v 值必须是切片、映射、通道、函数、指针、自由指针。
  
func (v Value) Pointer() uintptr
  

  
// 获取 v 值的地址。v 值必须是可寻址类型(CanAddr)。
  
func (v Value) UnsafeAddr() uintptr
  

  
// 将 UnsafePointer 类别的 v 值修改为 x,v 值必须是 UnsafePointer 类别,必须可修改。
  
func (v Value) SetPointer(x unsafe.Pointer)
  

  
// 判断 v 值是否为 nil,v 值必须是切片、映射、通道、函数、接口、指针。
  
// IsNil 并不总等价于 Go 的潜在比较规则,比如对于 var i interface{},i == nil 将返回
  
// true,但是 reflect.ValueOf(i).IsNil() 将 panic。
  
func (v Value) IsNil() bool
  

  
// 获取“指针所指的对象”或“接口所包含的对象”
  
func (v Value) Elem() reflect.Value
  

  
------------------------------
  

  
// 接口
  

  
// 获取“指针所指的对象”或“接口所包含的对象”
  
func (v Value) Elem() reflect.Value
  

  
------------------------------
  

  
// 通用
  

  
// 获取 v 值的字符串描述
  
func (v Value) String() string
  

  
// 获取 v 值的类型
  
func (v Value) Type() reflect.Type
  

  
// 返回 v 值的类别,如果 v 是空值,则返回 reflect.Invalid。
  
func (v Value) Kind() reflect.Kind
  

  
// 获取 v 的方法数量
  
func (v Value) NumMethod() int
  

  
// 根据索引获取 v 值的方法,方法必须存在,否则 panic
  
// 使用 Call 调用方法的时候不用传入接收者,Go 会自动把 v 作为接收者传入。
  
func (v Value) Method(int) reflect.Value
  

  
// 根据名称获取 v 值的方法,如果该方法不存在,则返回空值(reflect.Invalid)。
  
func (v Value) MethodByName(string) reflect.Value
  

  
// 判断 v 本身(不是 v 值)是否为零值。
  
// 如果 v 本身是零值,则除了 String 之外的其它所有方法都会 panic。
  
func (v Value) IsValid() bool
  

  
// 将 v 值转换为 t 类型,v 值必须可转换为 t 类型,否则 panic。
  
func (v Value) Convert(t Type) reflect.Value
  

  
------------------------------
  

  
// 示例
  
func main() {
  
var v reflect.Value      // 未包含任何数据
  
fmt.Println(v.IsValid()) // false
  

  
var i *int
  
v = reflect.ValueOf(i)   // 包含一个指针
  
fmt.Println(v.IsValid()) // true
  

  
v = reflect.ValueOf(nil) // 包含一个 nil 指针
  
fmt.Println(v.IsValid()) // false
  

  
v = reflect.ValueOf(0)   // 包含一个 int 数据
  
fmt.Println(v.IsValid()) // true
  
}
  

  
------------------------------
  

  
// 获取
  

  
// 获取 v 值的内容,如果 v 值不是有符号整型,则 panic。
  
func (v Value) Int() int64
  

  
// 获取 v 值的内容,如果 v 值不是无符号整型(包括 uintptr),则 panic。
  
func (v Value) Uint() uint64
  

  
// 获取 v 值的内容,如果 v 值不是浮点型,则 panic。
  
func (v Value) Float() float64
  

  
// 获取 v 值的内容,如果 v 值不是复数型,则 panic。
  
func (v Value) Complex() complex128
  

  
// 获取 v 值的内容,如果 v 值不是布尔型,则 panic。
  
func (v Value) Bool() bool
  

  
// 获取 v 值的长度,v 值必须是字符串、数组、切片、映射、通道。
  
func (v Value) Len() int
  

  
// 获取 v 值的容量,v 值必须是数值、切片、通道。
  
func (v Value) Cap() int
  

  
// 获取 v 值的第 i 个元素,v 值必须是字符串、数组、切片,i 不能超出范围。
  
func (v Value) Index(i int) reflect.Value
  

  
// 获取 v 值的内容,如果 v 值不是字节切片,则 panic。
  
func (v Value) Bytes() []byte
  

  
// 获取 v 值的切片,切片长度 = j - i,切片容量 = v.Cap() - i。
  
// v 必须是字符串、数值、切片,如果是数组则必须可寻址。i 不能超出范围。
  
func (v Value) Slice(i, j int) reflect.Value
  

  
// 获取 v 值的切片,切片长度 = j - i,切片容量 = k - i。
  
// i、j、k 不能超出 v 的容量。i = 4 { // 只列举 5 个
  
//fmt.Println("    ┗ ...")
  
//break
  
//}
  
}
  
fmt.Printf("    ┗ %v\n", v.Method(i).String())
  
// 通过名称获取方法
  
fmt.Println("MethodByName       :", v.MethodByName("String").String())
  
}
  
// ----- 可获取指针的类型 -----
  
switch v.Kind() {
  
case reflect.Slice, reflect.Map, reflect.Chan, reflect.Func,
  
reflect.Ptr, reflect.UnsafePointer:
  
fmt.Println("Pointer            :", v.Pointer())
  
}
  
// ----- 特殊类型 -----
  
switch v.Kind() {
  
// 指针:
  
case reflect.Ptr:
  
fmt.Println("=== 指针 ===")
  
// 获取指针地址
  
if !v.IsNil() {
  
// 获取指针所指对象
  
v = v.Elem() // 只有指针和接口类型可以使用 Elem()
  
fmt.Printf("转换到指针所指对象 : %v\n", v.Type())
  
// 递归处理指针所指对象
  
PrintValue(v)
  
return
  
}
  
// 自由指针:
  
case reflect.UnsafePointer:
  
fmt.Println("=== 自由指针 ===")
  
if v.Pointer() == 0 {
  
v.SetPointer(unsafePointer)
  
fmt.Println("重新指向新对象     :", v.Pointer())
  
}
  
// 将自由指针转换为 *ss 指针(因为定义 unsafePointer 时已经确定了类型)
  
s := (*ss)(v.Interface().(unsafe.Pointer))
  
// 获取反射值
  
v = reflect.ValueOf(s)
  
if !v.IsNil() {
  
// 获取指针所指对象
  
v = v.Elem() // 只有指针和接口类型可以使用 Elem()
  
fmt.Printf("转换到指针所指对象 : %v\n", v.Type())
  
// 递归处理指针所指对象
  
PrintValue(v)
  
return
  
}
  
// 接口:
  
case reflect.Interface:
  
fmt.Println("=== 接口 ===")
  
// 获取接口数据
  
fmt.Println("InterfaceData      :", v.InterfaceData())
  
// 获取接口所包含的对象
  
v = v.Elem() // 只有指针和接口类型可以使用 Elem()
  
fmt.Printf("转换到接口所含对象 : %v\n", v.Type())
  
// 递归处理接口的动态对象
  
PrintValue(v)
  
return
  
}
  
// ----- 简单类型 -----
  
// 有符号整型:
  
if reflect.Int  0 {
  
for j = 0; j < field.NumField()-1; j++ {
  
subfield := v.FieldByIndex([]int{i, j}) // 获取嵌套结构体字段
  
fmt.Printf("    │    ├ %-8v %v\n", subfield.Type(), subfield.String())
  
// if i >= 4 { // 只列举 5 个
  
// fmt.Println("        ┗ ...")
  
// break
  
// }
  
}
  
subfield := v.FieldByIndex([]int{i, j}) // 获取嵌套结构体字段
  
fmt.Printf("    │    └ %-8v %v\n", subfield.Type(), subfield.String())
  
}
  
// if i >= 4 { // 只列举 5 个
  
// fmt.Println("    ┗ ...")
  
// break
  
// }
  
}
  
field := v.Field(i) // 获取结构体字段
  
fmt.Printf("    └ %-8v %v\n", field.Type(), field.String())
  
// 通过名称查找字段
  
if v := v.FieldByName("ptr"); v.IsValid() {
  
fmt.Println("FieldByName(ptr)   :", v.Type().Name())
  
}
  
// 通过函数查找字段
  
v := v.FieldByNameFunc(func(s string) bool { return len(s) > 3 })
  
if v.IsValid() {
  
fmt.Println("FieldByNameFunc    :", v.Type().Name())
  
}
  
}
  
// 通道型:
  
case reflect.Chan:
  
fmt.Println("=== 通道型 ===")
  
// 发送数据(会阻塞)
  
v.Send(reflectValue)
  
// 尝试发送数据(不会阻塞)
  
fmt.Println("TrySend            :", v.TrySend(reflectValue))
  
// 接收数据(会阻塞)
  
if x, ok := v.Recv(); ok {
  
fmt.Println("Recv               :", x) //
  
}
  
// 尝试接收数据(不会阻塞)
  
if x, ok := v.TryRecv(); ok {
  
fmt.Println("TryRecv            :", x) //
  
}
  
// 因为要执行两次,通道和通道指针各执行一次,关闭后第二次就无法执行了。
  
// v.Close()
  
// 函数型:
  
case reflect.Func:
  
fmt.Println("=== 函数型 ===")
  
// 判断函数是否具有变长参数
  
if v.Type().IsVariadic() {
  
// 与可变参数对应的实参必须是切片类型的反射值(reflectArrayValue)。
  
fmt.Println("CallSlice          :", v.CallSlice([]reflect.Value{reflectArrayValue})) //
  
// 也可以用 v.Call 调用变长参数的函数,只需传入 reflectValue 即可。
  
} else {
  
// 根据函数定义的参数数量,传入相应数量的反射值(reflectValue)。
  
fmt.Println("Call               :", v.Call([]reflect.Value{reflectValue})) //
  
}
  
}
  
}
  

  
------------------------------------------------------------
  

  

  

  




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-594247-1-1.html 上篇帖子: Golang学习 - regexp 包 下篇帖子: golang slice 切片原理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表