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

本文来自:CSDN博客

感谢作者:mrseasons

查看原文:go 速学 - 14 - 反射

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。