go 速学 - 14 - 反射

目录

摘要

使用反射,匿名字段,动态修改属性,动态调用方法

反射 reflection

使用反射

前提

使用反射之前必须引用包 reflect

定义一个结构及方法
import "reflect"

type User struct {
    Id   int
    Name string
    Age  int
}

func (u User) say() {
    fmt.Println("hello")
}
u := User{Id: 1, Name: "Peter", Age: 20}
反射所有字段及方法
  • reflect.TypeOf(o) 用于获得类型原型
  • reflect.ValueOf(o) 用于获得值

注意要想访问字段的值则字段应为 public,要想调用方法则方法应为 public

func info(o interface{}) {
    //获得参数类型的原型
    t := reflect.TypeOf(o)
    fmt.Println("t", t)                       //t main.User
    fmt.Println("t.Name()", t.Name())         //t.Name() User
    fmt.Println("t.NumField()", t.NumField()) //t.NumField() 3

    v := reflect.ValueOf(o)
    fmt.Println("v", v) //v <main.User Value>

    //检测类型
    if k := t.Kind(); k != reflect.Struct {
        return
    }

    //输出属性
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        //此时的 Field 必须为public
        val := v.Field(i).Interface()
        fmt.Println(f.Name, f.Type, val)
        //--> outputs
        //Id int 1
        //Name string Peter
        //Age int 20
    }
    fmt.Println()

    //输出方法
    for i := 0; i < t.NumMethod(); i++ {
        m := t.Method(i)
        fmt.Println(m.Name, m.Type)
        //-->outputs
        //say func(main.User)
    }
}
info(u)

访问结构中的匿名字段

type Manager struct {
    User
    title string
}
//type
m := Manager{title: "Manager", User: User{Id: 2, Name: "Jane", Age: 22}}
t := reflect.TypeOf(m)
f := t.FieldByIndex([]int{0, 1})
fmt.Println("f", f.Name, f.Type) //f Name string

//value
v := reflect.ValueOf(m)
val := v.FieldByIndex([]int{0, 1}).Interface()
fmt.Println("val", val) //val Jane

使用 reflect.FieldByIndex() 方法,该方法的参数为 slice,以上第一个位置的 “0” 表示 Manager 的0号属性(User),1表示 User 的1号属性(Name)

动态修改属性的值

func set(o interface{}) {
    v := reflect.ValueOf(o)
    判断是否为指针类型且可写
    if k := v.Kind(); k != reflect.Ptr || !v.Elem().CanSet() {
        fmt.Println("invalid type")
        return
    }
    v = v.Elem()
    f := v.FieldByName("Name")

    //判断指定属性是否存在
    if !f.IsValid() {
        fmt.Println("invalid name")
        return
    }
    if f.Kind() == reflect.String {
        f.SetString("a")
    }
}

u := User{Id: 1, Name: "Peter", Age: 20}
fmt.Println("u.Name", u.Name) //u.Name Peter
set(&u)
fmt.Println("u.Name", u.Name) //u.Name a
set(u)

注意以上是通过传入指针来实现动态修改的

动态调用方法

注意调用方法时该方法应为 public

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

u := User{Id: 1, Name: "Peter", Age: 20}
v = reflect.ValueOf(u)
mn := v.MethodByName("Hello")
args := []reflect.Value{reflect.ValueOf("Andy")}
mn.Call(args)
fmt.Println("u.Name", u.Name) //hello  Andy  my name is  a
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值