Golang 反射
反射是指程序运行期间对程序本身进行访问和修改的能力
变量的内在机制
- 变量包含类型信息和值信息
- 类型信息:是静态的元信息,是预先定义好的
- 值信息:是程序运行过程中动态改变的
反射的使用
- reflect 包封装了反射相关的方法
- 获取类型信息:reflect.TypeOf,是静态的
- 获取值信息:reflect.ValueOf,是动态的
空接口与反射
- 反射可以在运行时动态获取程序的各种详细信息
- 反射获取 interface 类型信息
package main
import (
"fmt"
"reflect"
)
// 反射获取interface类型
func relect_type(i interface{}) {
// typeOf不能直接比较
t := reflect.TypeOf(i)
fmt.Println("类型是: ", t)
// kind() 可以获取具体类型
k := t.Kind()
fmt.Println(k)
switch k {
case reflect.Float64:
fmt.Println("i is float64")
case reflect.String:
fmt.Println("i is string")
}
}
func main() {
var x float64 = 2.4
relect_type(x)
}
反射获取 interface 值信息
package main
import (
"fmt"
"reflect"
)
// 反射获取interface值信息
func relect_value(i interface{}) {
v := reflect.ValueOf(i)
fmt.Println(v)
k := v.Kind()
switch k {
case reflect.Float64:
fmt.Println("a is: ", v.Float())
}
}
func main() {
var x float64 = 3.14
relect_value(x)
}
反射修改值信息
package main
import (
"fmt"
"reflect"
)
// 反射修改值信息
func reflect_set_value(i interface{}) {
v := reflect.ValueOf(i)
k := v.Kind()
switch k {
case reflect.Float64:
// 值传递无法在反射中修改
// 反射修改值
v.SetFloat(99.81)
fmt.Println("value is, ", v.Float())
case reflect.Ptr:
// Elem()获取地址中的值
v.Elem().SetFloat(88.91)
fmt.Println("ptr value is, ", v.Elem().Float())
// 地址
fmt.Println(v.Pointer())
}
}
func main() {
var x float64 = 3.14
// 反射值类型, 值传递无法在反射中修改
//reflect_set_value(x)
//fmt.Println("main value, ", x)
// 反射一个指针类型
reflect_set_value(&x)
fmt.Println("ptr main value, ", x)
}
结构体反射
查看类型、字段和方法
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type User struct {
Id int
Name string
Age int
}
// 绑定方法
func (u User) Hello() {
fmt.Println("hello")
}
func reflect_struct(i interface{}) {
t := reflect.TypeOf(i)
fmt.Println("类型: ", t)
fmt.Println("字符串类型: ", t.Name())
// 获取值
v := reflect.ValueOf(i)
fmt.Println("值: ", v)
// 获取结构体所有属性
// 获取结构体字段个数: t.NumField()
for i := 0; i < t.NumField(); i++ {
// 取每个字段
// 通过interface{} 的 TypeOf()获取
f := t.Field(i)
// f.Name 字段名称 f.Type 字段类型
fmt.Printf("%s : %v\t", f.Name, f.Type)
// 获取字段值信息
// 通过interface{} 的 ValueOf()获取
// interface() 获取字段对应的值
val := v.Field(i).Interface()
fmt.Println("val: ", val)
}
// 获取方法
// NumMethod(), 获取方法个数
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
fmt.Println("方法名称: ", m.Name)
fmt.Println("方法类型: ", m.Type)
}
}
func main() {
u := User{1, "zs", 20}
reflect_struct(u)
}
查看匿名字段
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type User struct {
Id int
Name string
Age int
}
type Boy struct {
User
Addr string
}
func main() {
m := Boy{User{1, "zs", 20}, "bj"}
t := reflect.TypeOf(m)
fmt.Println(t)
// 匿名
fmt.Printf("%#v\n", t.Field(0))
// 值信息
fmt.Println("%#\n", reflect.ValueOf(m).Field(0))
}
修改结构体值
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type User struct {
Id int
Name string
Age int
}
// 修改结构体值
func SetValue(i interface{}) {
v := reflect.ValueOf(i)
// 指针类型重新赋值
v = v.Elem()
// 取字段
f := v.FieldByName("Name")
if f.Kind() == reflect.String {
f.SetString("lisi")
}
}
func main() {
u := User{1, "zs", 20}
SetValue(&u)
fmt.Println(u)
}
调用方法
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type User struct {
Id int
Name string
Age int
}
func (u User) Hello(name string) {
fmt.Println("hello: ", name)
}
func main() {
u := User{1, "zs", 20}
v := reflect.ValueOf(u)
// 获取方法
m := v.MethodByName("Hello")
// 构建参数
args := []reflect.Value{reflect.ValueOf("wangwu")}
m.Call(args)
}
获取字段 tag
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string `json:"name01" db:"name02"`
}
func main() {
var s Student
v := reflect.ValueOf(&s)
// 类型
t := v.Type()
// 获取字段
f := t.Elem().Field(0)
// 获取tag
fmt.Println(f.Tag.Get("json"))
fmt.Println(f.Tag.Get("db"))
}