美文网首页
第八节反射reflection

第八节反射reflection

作者: barriers | 来源:发表于2019-12-29 13:56 被阅读0次

1.基本概念

1.反射可以大大提高程序的灵活性,使得接口interface{}有更大的发挥余地;
2.反射使用typeof和valueof函数从接口中获取目标对象信息;
3.反射会将匿名字段作为独立字段(匿名字段本质)
4.想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface;
5.通过反射可以"动态"调用方法。

值和方法反射

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

func (u User) Hello(){
    fmt.Println("Hello world")
}

func main()  {
    u := User{1, "雪飞霜", 18}
    Info(u)
}

func Info(o interface{}){
    t := reflect.TypeOf(o)
    fmt.Println("Type:", t.Name())
// 判断是否是指针类型,是指针类型直接结束运算
    if k:= t.Kind();k!=reflect.Struct{
        fmt.Println("XX")
        return
    }
    v := reflect.ValueOf(o)
    fmt.Println("Fields:")
    //获取某个对象的字段信息及类型信息及其值
    for i:=0;i<t.NumField();i++{
        f:=t.Field(i)
        val := v.Field(i).Interface()
        //printf要在需要格式化的地方输出,其他直接输出变量或者直接输出字符串的可以直接用println
        fmt.Printf("%6s: %v = %v\n", f.Name, f.Type, val)
    }
    // 获取对象的方法信息
    for i:=0; i<t.NumMethod();i++{
        m:=t.Method(i)
        fmt.Printf("%6s: %v\n", m.Name, m.Type)
    }
}

匿名字段中的信息获取

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

type Manger struct {
    User
    title string
}

func (u User) Hello(){
    fmt.Println("Hello world")
}

func main()  {

    m := Manger{User: User{1, "毒士", 12}, title: "贾诩"}
    t := reflect.TypeOf(m)
 // 取匿名字段信息(下标为0的为User类型的字段)
    fmt.Printf("%#v\n", t.Field(0))
// 取非匿名字段信息(小标为1的title)
    fmt.Printf("%#v\n", t.Field(1))
    // 获取匿名字段中的Id信息(下标为0的字段的下标为0的字段)
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,0}))
}

用reflect修改一个整形的值

通过反射对接口中的对象的值进行修改

import (
    "fmt"
    "reflect"
)

func main()  {

    m := 123
 //必须传入指针,否则修改不了值
    v := reflect.ValueOf(&m)
 //修改为999
    v.Elem().SetInt(999)
 //输出为999
    fmt.Printf(x)
}

用reflect修改一个基本类型的值

通过反射对接口中的对象的值进行修改

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

func (u interface{}) Set(){
    v := reflect.ValueOf(u)
    // 判断对象是不是pointer-interface并且是可设值的
    if v.Kind()==reflect.Ptr&&!v.Elem().CanSet(){
        fmt.Println("XXX")
        return
    } else {
        // 因为都是value类型的,所以可以直接赋值
        v = v.Elem()
    }
    // 通过字段名字取值
    if f:=v.FieldByName("Name");f.Kind()==reflect.String{
        f.SetString("BYBYBY")
    }
    
    fmt.Println("Hello world")
}

func main()  {
    m := User{1, "孙鲁班", 12}
    Set(&m)
    fmt.Printf(m)
}

根据不确定的属性修改值

通过反射对接口中的对象的值进行修改
通过sValid判断是否有该属性

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

func (u interface{}) Set(){
    v := reflect.ValueOf(u)
    // 判断对象是不是pointer-interface并且是可设值的
    if v.Kind()==reflect.Ptr&&!v.Elem().CanSet(){
        fmt.Println("XXX")
        return
    } else {
        // 因为都是value类型的,所以可以直接赋值
        v = v.Elem()
    }
    // 通过字段名字取值
    f:=v.FieldByName("Name")
    // 判断结构体中是否有该字段,没有则返回,有则修改值
    if !f.IsValid(){
        fmt.Println("BAD")
        return
    }
    if f.Kind()==reflect.String{
        f.SetString("BYBYBY")
    }
    
    fmt.Println("Hello world")
}

func main()  {
    m := User{1, "孙鲁班", 12}
    Set(&m)
    fmt.Printf(m)
}

通过反射动态调用方法

正常调用

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

func main()  {
    u := User{1, "雪飞霜", 18}
    u.HelloUser("alice")
}

func (u User) HelloUser(name string){
    fmt.Println("Hello", name, "my name is", u.Name)
}

反射调用

import (
    "fmt"
    "reflect"
)

type User struct {
    ID int
    Name string
    Age int
}

func main()  {
    u := User{1, "雪飞霜", 18}
    v := reflect.ValueOf(u)
    mv := v.MethodByName("HelloUser")
    args := []reflect.Value{reflect.ValueOf("alice")}
    mv.Call(args)
}

func (u User) HelloUser(name string){
    fmt.Println("Hello", name, "my name is", u.Name)
}

练习

定义一个结构,通过反射来打印其信息,并调用方法,获取方法返回值,并对返回值进行其他操作。

相关文章

网友评论

      本文标题:第八节反射reflection

      本文链接:https://www.haomeiwen.com/subject/sugsoctx.html