zoukankan      html  css  js  c++  java
  • golang反射

    反射reflection

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

    对某一个struct进行反射的基本操作

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int
        Name string
        Age  int
    }
    
    func (u User) Hello() {
        fmt.Println("Hello world!")
    }
    func Info(o interface{}) {
        t := reflect.TypeOf(o)         //反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
        fmt.Println("Type:", t.Name()) //调用t.Name方法来获取这个类型的名称
    
        v := reflect.ValueOf(o) //打印出所包含的字段
        fmt.Println("Fields:")
        for i := 0; i < t.NumField(); i++ { //通过索引来取得它的所有字段,这里通过t.NumField来获取它多拥有的字段数量,同时来决定循环的次数
            f := t.Field(i)               //通过这个i作为它的索引,从0开始来取得它的字段
            val := v.Field(i).Interface() //通过interface方法来取出这个字段所对应的值
            fmt.Printf("%6s:%v =%v
    ", f.Name, f.Type, val)
        }
        for i := 0; i < t.NumMethod(); i++ { //这里同样通过t.NumMethod来获取它拥有的方法的数量,来决定循环的次数
            m := t.Method(i)
            fmt.Printf("%6s:%v
    ", m.Name, m.Type)
    
        }
    }
    func main() {
        u := User{1, "Jack", 23}
        Info(u)
    }
    

    判断传入的类型是否是我们想要的类型

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int
        Name string
        Age  int
    }
    
    func (u User) Hello() {
        fmt.Println("Hello world!")
    }
    func Info(o interface{}) {
        t := reflect.TypeOf(o)                  //反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
        fmt.Println("Type:", t.Name())          //调用t.Name方法来获取这个类型的名称
        if k := t.Kind(); k != reflect.Struct { //通过kind方法判断传入的类型是否是我们需要反射的类型
            fmt.Println("xx")
            return
        }
        v := reflect.ValueOf(o) //打印出所包含的字段
        fmt.Println("Fields:")
        for i := 0; i < t.NumField(); i++ { //通过索引来取得它的所有字段,这里通过t.NumField来获取它多拥有的字段数量,同时来决定循环的次数
            f := t.Field(i)               //通过这个i作为它的索引,从0开始来取得它的字段
            val := v.Field(i).Interface() //通过interface方法来取出这个字段所对应的值
            fmt.Printf("%6s:%v =%v
    ", f.Name, f.Type, val)
        }
        for i := 0; i < t.NumMethod(); i++ { //这里同样通过t.NumMethod来获取它拥有的方法的数量,来决定循环的次数
            m := t.Method(i)
            fmt.Printf("%6s:%v
    ", m.Name, m.Type)
    
        }
    }
    func main() {
        u := User{1, "Jack", 23}
        Info(u)
    }
    

    反射 匿名或嵌入字段

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int
        Name string
        Age  int
    }
    
    type Manager struct {
        User  //反射会将匿名字段作为一个独立字段来处理
        Title string
    }
    
    func main() {
        m := Manager{User: User{1, "Jack", 12}, Title: "123"}
        t := reflect.TypeOf(m)
        fmt.Printf("%#v
    ", t.Field(0))                   //#号会将reflect的struct的详情页打印出来,可以看出来这是一个匿名字段
        fmt.Printf("%#v 
    ", t.FieldByIndex([]int{0, 0})) //此时 我们就可以将User当中的ID取出来,这里面需要传进方法中的是一个int类型的slice,User相对于manager索引是0,id相对于User索引也是0
        fmt.Printf("%v 
    ", t.FieldByIndex([]int{0, 1}))
        v := reflect.ValueOf(m)
        fmt.Printf("%#v
    ", v.Field(0))
    }
    

    通过反射修改struct中的内容

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    func main() {
        x := 123
        v := reflect.ValueOf(&x)   
        //传递指针才能修改
        v.Elem().SetInt(999)
        fmt.Println(x)
    }
    PS G:mygosrcmytest> go run .temp10.go
    999
    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int
        Name string
        Age  int
    }
    
    func main() {
        u := User{1, "Tom", 12}
        Set(&u)
        fmt.Println(u)
    
    }
    
    func Set(o interface{}) {
        v := reflect.ValueOf(o)
        if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
            fmt.Println("xxx")
            return
        } else {
            v = v.Elem()
        }
        f := v.FieldByName("Name")
        if !f.IsValid() {
            fmt.Println("xiugaishibai")
        }
        if f.Kind() == reflect.String {
            f.SetString("jACK")
        }
    
    }
    

    通过发射进行方法的调用 动态调用方法

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int
        Name string
        Age  int
    }
    
    func (u User) Hello(name string) {
        fmt.Println("Hello", name, "My name is", u.Name)
    }
    
    func main() {
        u := User{1, "OK", 12}
        v := reflect.ValueOf(u)
        mv := v.MethodByName("Hello")
        args := []reflect.Value{reflect.ValueOf("JOE")}
        mv.Call(args)
    }
  • 相关阅读:
    Using CocoaPods
    IMPROVING IOS UNIT TESTS WITH OCMOCK
    梦想不为斗室所缚
    【转】class 'org.springframework.orm.hibernate3.LocalSessionFactoryBean' not found解决办法
    我们去工作是为了什么?——迈锡尼
    查看已保存的wifi密码
    点球成金
    研究生开口月薪一万 企业暗示“靠边站”
    程序员技术练级攻略
    Emacs是一种信仰!世界最强编辑器介绍 (转自王珢)
  • 原文地址:https://www.cnblogs.com/craneboos/p/8945150.html
Copyright © 2011-2022 走看看