一、通过反射获取类型信息

在 Go 程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息。

package main

import (
"fmt"
"reflect"
) func test1() {
var a int
t := reflect.TypeOf(a)
fmt.Printf("name:%v kind:%v\n", t.Name(), t.Kind()) // name:int kind:int
} func test2() {
type User struct {}
user := User{}
t := reflect.TypeOf(user)
fmt.Printf("name:%v kind:%v\n", t.Name(), t.Kind()) // name:User kind:struct
} func main() {
test1()
test2()
}

二、通过反射获取指针指向的元素类型

package main

import (
"fmt"
"reflect"
) func main() {
// 声明一个空结构体
type User struct {}
// 创建User的实例
user := &User{}
// 获取结构体实例的反射类型对象
t := reflect.TypeOf(user)
// 显示反射类型对象的名称和种类
fmt.Printf("name:'%v' kind:'%v'\n", t.Name(), t.Kind()) // name:'' kind:'ptr'
// 获取指针类型的元素类型
e := t.Elem()
// 显示指针变量指向元素的类型名称和种类
fmt.Printf("name:'%v' kind:'%v'\n", e.Name(), e.Kind()) // name:'User' kind:'struct'
}

三、通过反射获取结构体的成员类型

任意值通过 reflect.TypeOf() 获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的 NumField() 和 Field() 方法获得结构体成员的详细信息。

package main

import (
"fmt"
"reflect"
) type User struct {
Name string `json:"username"`
Age int
Salary float64
} func main() {
user := User{"pd", 18, 9999.99}
tf := reflect.TypeOf(user)
// 遍历结构体所有成员
for i := 0; i < tf.NumField(); i++ {
// 获取每个成员的结构体字段类型
fieldType := tf.Field(i)
fmt.Printf("name:'%v' tag:'%v'\n", fieldType.Name, fieldType.Tag)
// name:'Name' tag:'json:"username"'
// name:'Age' tag:''
// name:'Salary' tag:''
}
// 通过字段名, 找到字段类型信息
userType, ok := tf.FieldByName("Name")
if ok {
// 从tag中取出需要的tag
fmt.Println(userType.Tag.Get("json")) // username
}
}

四、通过反射获取值信息

package main

import (
"fmt"
"reflect"
) func main() {
// 声明整型变量a并赋初值
var a int
a = 666
// 获取变量a的反射值对象
vf := reflect.ValueOf(a)
// 将vf反射值对象以Interface{}类型取出, 通过类型断言转换为int类型
r1 := vf.Interface().(int)
// 将vf反射值对象以int64类型取出
r2 := vf.Int()
// 强制类型转换为int类型
r3 := int(r2)
fmt.Printf("r1值:%v r1类型:%T\n", r1, r1) // r1值:666 r1类型:int
fmt.Printf("r2值:%v r2类型:%T\n", r2, r2) // r2值:666 r2类型:int64
fmt.Printf("r3值:%v r3类型:%T\n", r3, r3) // r3值:666 r3类型:int
}

五、通过反射访问结构体成员的值

package main

import (
"fmt"
"reflect"
) type User struct {
Name string
Age int
Salary float64
} func main() {
user := User{"pd", 18, 9999.99}
vf := reflect.ValueOf(user)
// 获取字段数量
fmt.Printf("NumField:%v\n", vf.NumField()) // NumField:3
// 获取索引为2的字段
field := vf.Field(2)
fmt.Println(field.Type()) // float64
// 根据名字查找字段
fbn := vf.FieldByName("Name")
fmt.Println(fbn.Type()) // string
// 根据索引查找字段
fbi := vf.FieldByIndex([]int{1})
fmt.Println(fbi.Type()) // int
}

六、判断反射值的空和有效性

package main

import (
"fmt"
"reflect"
) func main() {
// *int的空指针
var a *int
fmt.Println(reflect.ValueOf(a).IsNil()) // true // nil值
fmt.Println(reflect.ValueOf(nil).IsValid()) // false // 实例化一个结构体
s := struct{}{}
// 尝试从结构体中查找一个不存在的字段
fmt.Println(reflect.ValueOf(s).FieldByName("").IsValid()) // false // 尝试从结构体中查找一个不存在的方法
fmt.Println(reflect.ValueOf(s).MethodByName("").IsValid()) // false
}

七、通过反射修改变量的值

package main

import (
"fmt"
"reflect"
) func main() {
// 声明整型变量a并赋初值
var a int
var b string
a = 100
b = "哈哈哈"
// 获取变量a、b的反射值对象(a、b的地址)
vfa := reflect.ValueOf(&a)
vfb := reflect.ValueOf(&b)
// 取出a、b地址的元素(值)
vfae := vfa.Elem()
vfbe := vfb.Elem()
// 修改a、b的值
vfae.SetInt(200)
vfbe.SetString("嘻嘻嘻")
// 打印a、b的值
fmt.Println(a, b) // 200 嘻嘻嘻
}
package main

import (
"fmt"
"reflect"
) type User struct {
Name string
Age int
} func main() {
user := User{"pd", 18}
vf := reflect.ValueOf(&user)
// 取出User实例地址的元素
vfe := vf.Elem()
// 获取Name字段的值
name := vfe.FieldByName("Name")
// 修改此实例(对象)对应字段的值
name.SetString("佩奇")
fmt.Println(user) // {佩奇 18}
}

八、通过类型信息创建实例

package main

import (
"fmt"
"reflect"
) func main() {
var a int
// 取变量a的反射类型对象
tf := reflect.TypeOf(a)
// 根据反射类型对象创建这个类型的实例值,值以 reflect.Value 类型返回
obj := reflect.New(tf)
// 输出类型和种类
fmt.Printf("type:%v kind:%v\n", obj.Type(), obj.Kind()) // type:*int kind:ptr
}

九、通过反射调用函数、方法

package main

import (
"fmt"
"reflect"
) // add函数
func add(a, b int) int {
return a + b
} func main() {
// 将函数包装为反射值对象
vf := reflect.ValueOf(add)
// 构造函数参数, 传入两个整型值
paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}
// 反射调用函数
retList := vf.Call(paramList)
// 获取第一个返回值, 取整数值
fmt.Println(retList[0].Int()) //
}
package main

import (
"fmt"
"reflect"
) type User struct {
Name string
} func (u *User) Hello(name string) {
fmt.Printf("%s对%s打了一个招呼...\n", u.Name, name) // pd对佩奇打了一个招呼...
} func main() {
user := User{"pd"}
vf := reflect.ValueOf(&user)
method := vf.MethodByName("Hello")
// 方式1
// args := []reflect.Value{reflect.ValueOf("佩奇")}
// 方式2
var args []reflect.Value
args = append(args, reflect.ValueOf("佩奇"))
// 调用方法
method.Call(args)
}

最新文章

  1. python简单文件操作
  2. PHP生成二维码库phpqrcode
  3. spring-cloud-hystrix熔断
  4. 页面点击关闭弹出提示js代码
  5. Eclipse-cdt 配合 gdbserver 进行 arm 程序远程调试 下
  6. 安卓开发-使用XML菜单布局简单介绍
  7. 聊聊RPC及其原理
  8. Windows下设置 ssh key,配置GitHub ssh key
  9. Atom以及amWiki个人维基安装设置
  10. 腾讯广告联盟 Android SDK(广点通)demo的使用方式
  11. MyBatis - 10.MyBatis扩展
  12. Visual Studio Code--开发大大们都在用的编辑器
  13. wx小程序横向滚动
  14. Swing获取字符串的宽度和高度
  15. Java中线程同步的理解 - 其实应该叫做Java线程排队
  16. &#39;Install app for SharePoint&#39;: Sideloading of apps is not enabled on this site
  17. 【BZOJ】1651: [Usaco2006 Feb]Stall Reservations 专用牛棚(线段树/前缀和 + 差分)
  18. 读取xml文件,写入excel
  19. 【MVC+MySQL+EntityFramework】查询性能优化笔记
  20. XPath注入技术综述

热门文章

  1. hdu 3172 Virtual Friends (字符串的并查集)
  2. the little schemer 笔记(0)
  3. size_t与size_type区别
  4. python之list操作
  5. 144 Binary Tree Preorder Traversal 二叉树的前序遍历
  6. Android屏幕适配-安卓切图
  7. (026)[工具软件]剪切板管理:Ditto
  8. java设计模式之单例设计模式
  9. 【转】10种简单的Java性能优化
  10. 登录脚本重构by封装