反射

作者: 风铃草613 | 来源:发表于2020-08-20 17:35 被阅读0次

反射可以在运行时获取对象的类型信息和内存结构。反射操作所需的全部信息来自于接口变量,接口变量除存储自身类型外,还会保存实际对象的类型信息。

func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value

类型

Name & Kind

Name获取静态类型,Kind获取的是底层类型;在自定义类型的变量中获取到的值是不一样的。

type NewInt int
var x NewInt = 100
t := reflect.TypeOf(x)
fmt.Println(t, t.Name(), t.Kind()) // main.NewInt NewInt int

Kind支持的类型如下所示:

const (
    Invalid Kind = iota
    Bool
    Int
    Int8
    Int16
    Int32
    Int64
    Uint
    Uint8
    Uint16
    Uint32
    Uint64
    Uintptr
    Float32
    Float64
    Complex64
    Complex128
    Array
    Chan
    Func
    Interface
    Map
    Ptr
    Slice
    String
    Struct
    UnsafePointer
)
指针类型

传入对象分区为基类型和指针类型,他们并不属于同一类型。方法Elem返回指针、数组、切片、通道、字典(值)的基类型。

type NewInt int
var x NewInt = 100
tx, tp := reflect.TypeOf(x), reflect.TypeOf(&x)
fmt.Println(tx.Kind(), tp.Kind(), tx == tp, tx == tp.Elem()) // int ptr false true

不同基类型的指针也是不等的

var x rune = 100
var y uint32 = 100
tx, ty := reflect.TypeOf(&x), reflect.TypeOf(&y)
fmt.Println(tx.Kind(), ty.Kind(), tx == ty, tx.Elem() == ty.Elem()) // ptr ptr false false
结构体类型

只有在获取结构体指针的基类型后才能对其遍历

type user struct {
    name string
    age  int
}

type manager struct {
    user
    title string
}

func main() {
    m := &manager{user{"Jack", 18}, "boss"}
    t := reflect.TypeOf(m)
    if t.Kind() == reflect.Ptr { // 获取指针的基类型
        t = t.Elem()
    }
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        fmt.Println(f.Type)
        if f.Anonymous { // 输出匿名字段信息(user)
            for j := 0; j < f.Type.NumField(); j++ {
                subf := f.Type.Field(j)
                fmt.Println(subf.Type)
            }
        }
    }
}

/*
main.user
string
int
string
*/

FieldNumField可以访问当前包或者外包的非导出结构成员。

var s http.Server
t := reflect.TypeOf(s)
for i := 0; i < t.NumField(); i++ {
    fmt.Println(t.Field(i).Name)
}
// Addr,Handler,TLSConfig,ReadTimeout,ReadHeaderTimeout,WriteTimeout,IdleTimeout,MaxHeaderBytes,TLSNextProto,ConnState,ErrorLog,BaseContext,ConnContext,disableKeepAlives,inShutdown,nextProtoOnce,nextProtoErr,mu,listeners,activeConn,doneChan,onShutdown,

对于匿名字段,也可以通过FieldByNameFieldByIndex直接访问

type user struct {
    name string
    age  int
}

type manager struct {
    user
    title string
}

func main() {
    m := manager{user{"Jack", 18}, "boss"}
    t := reflect.TypeOf(m)
    name, exists := t.FieldByName("name") // 多级访问时无法访问嵌套的同名字段
    if exists {
        fmt.Println(name.Type) // string
    }
    sex, exists := t.FieldByName("sex")
    if exists {
        fmt.Println(sex.Type)
    }
    age := t.FieldByIndex([]int{0, 1}) // 支持多级访问
    fmt.Println(age.Type)
}

输出方法集(FIX)

struct tag

利用反射提取struct tag,常用于ORM映射或者数据格式验证。

type user struct {
    name string `field:"name" type:"varchar(50)"`
    age  int    `field:"age" type:"int"`
}

func main() {
    var u user
    t := reflect.TypeOf(u)
    for i := 0; i < t.NumField(); i++ {
        attr := t.Field(i)
        fmt.Println(attr.Tag.Get("field"), attr.Tag.Get("type"))
    }
}
// name varchar(50)
// age int

相关文章

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • 镜面反射矩阵的推导

    镜面反射是以镜面作为反射平面,实物与反射物到反射平面的距离相等,实物与反射物方向相反,所以,反射矩阵由反射平面确定...

  • reflect.go包学习_之二 指针操作提高反射性能 反射应用

    reflect.go包学习_之二 指针操作提高反射性能 反射应用 反射创建实例 反射信息、反射调用方法、反射修改值...

  • Java互联网公司-经典面试题附答案

    基础:Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?优点:反射具有解耦性,缺点:反射属...

  • Java反射与joor反射库的使用

    java原生反射的使用 反射构造对象 反射方法 反射字段 joor反射库的使用 github:https://gi...

  • Java反射

    什么是反射? 反射的作用? 反射性能优化?

  • 反射三定律

    反射第一定律:反射可以将interface类型变量转换成反射对象 反射第二定律:反射可以将反射对象还原成inter...

  • 反射

    1.反射是什么?反射的定义,概念 2.为什么要学反射? 3.怎么使用反射?反射的使用

  • 一周岁前做好两件事,孩子就不会语言迟缓,保证口齿伶俐

    与语言发展相关的原始反射有四个:张口反射、足跖反射、抓握反射和手拉反射,每个反射的发生、发展和整合都是次第进行的,...

  • 面试官问go反射第一弹

    目录 反射概念 reflect包 反射类型(Type)和种类(Kind) 反射类型(Type)使用 反射类型对象(...

网友评论

      本文标题:反射

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