Go:反射

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

在 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()
}
View Code

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

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'
}
View Code

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

任意值通过 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
    }
}
View Code

四、通过反射获取值信息

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
}
View Code

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

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
}
View Code

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

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
}
View Code

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

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 嘻嘻嘻
}
View Code
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}
}
View Code

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

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
}
View Code

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

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()) // 30
}
View Code
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)
}
View Code

 

posted @ 2019-06-04 22:09  就俗人一个  阅读(369)  评论(0编辑  收藏  举报