美文网首页
Go语言基础——反射

Go语言基础——反射

作者: 北枫晴天 | 来源:发表于2018-07-13 07:13 被阅读0次

Go语言提供了一种机制,在编译时不知道类型的情况下,在运行时,可更新变量、查看值、调用方法以及直接对它的结构成员进行操作,这种机制称为反射(reflection)。

1、Go的反射程序包:reflect

反射功能由reflect包提供,包内定义了两个重要的类型:Type和Value。
Type表示Go语 言的一个类型,它是一个有很多方法的接口,这些方法可以用来识别类型以及透视类型的组 成部分,比如一个结构的各个字段或者一个函数的各个参数。reflect.Type接口只有一个实现,即类型描述符,接口值中的动态类型也是类型描述符。
reflect.Value可以包含一任意类型的值。

通过示例展示Type和Value的使用

package main 

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,"Tom",12}
//  Info(&u) 传入指针类型,编译报错:panic: reflect: NumField of non-struct type
    Info(u) // 通过值拷贝输入对象
}

// 反射示例函数
func Info(o interface{}) {
    t := reflect.TypeOf(o)  // 获取类型数据
    fmt.Println("Type:", t.Name()) // 打印类型名称
    
    v := reflect.ValueOf(o) // 获取对象的数值
    fmt.Println("Fields:")
    
    for i :=0; i < t.NumField(); i++ {
        f := t.Field(i) // 获取指定索引结构成员的信息
        val := v.Field(i).Interface()   // 获取指定结构成员的值
        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) // 打印方法的名称,方法声明
    }
}

程序运行输出的结果如下图:


图片.png

2、匿名字段的反射

在Go语言中,可以通过索引来获取匿名字段的信息,参见程序代码:

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, "Lisa", 28}, title: "CFO"}   // 对象定义及匿名User类型字段初始化
    t := reflect.TypeOf(m)  // 获取对象的类型信息
    
    fmt.Printf("%#v\n", t.Field(0)) // 通过索引获取匿名字段的信息
    fmt.Printf("%#v\n", t.Field(1)) // 获取title字段的信息
    
    // 获取匿名User类型字段成员的方法,通过传入slice来制定索引对应的成员,可以获取相应的信息
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,0})) //获取User中的Id成员
    fmt.Printf("%#v\n", t.FieldByIndex([]int{0,1})) //获取User中的Name成员
}

运行输出结果:


图片.png

上图中,可以看到,对于User类型的匿名成员的名称为:User,是否匿名Anonymous标记为:true,而对于User成员Id和Name来讲,匿名标记为false。

3、通过反射修改结构对象的值

package main 

import (
    "fmt"
    "reflect"   //引入反射包
)

// 定义用户结构
type User struct {
    Id int
    Name string
    Age int
}

func main() {
    u := User{1,"Tom", 28}
    fmt.Println("before:",u)
    Set(&u)
    fmt.Println("after:",u)
}

func Set(o interface{}) {
    v := reflect.ValueOf(o)
    
    if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
        fmt.Print("输入的对象是不可修改的")
    } else {
        v = v.Elem()
    }
     // 判断是否获取到制定名称的字段信息
    f := v.FieldByName("Name")
    if !f.IsValid() {
        fmt.Println("没有找到Name的字段")
        return
    }
    // 修改字段的数值
    if f.Kind() == reflect.String {
        f.SetString("Tom2")
    } 
    
}

运行结果如下:

图片.png

reflect 包中还有很多有用的方法,具体详见包的参考文档及源码

相关文章

  • Go语言基础——反射

    Go语言提供了一种机制,在编译时不知道类型的情况下,在运行时,可更新变量、查看值、调用方法以及直接对它的结构成员进...

  • Go 语言基础--反射 浅析

    前言 反射是众多编程语言中的一个非常实用的功能,毫不意外go 也是对于反射提供了友好的支持,反射官方描述是一种能够...

  • Go语言基础之反射

    变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息。 值信息:程序运行过程中可动态变化...

  • golang 反射机制

    go语言也有反射机制,今天自学到go的反射,发现还是很值得记录一些这个知识点的。go语言它是通过 reflect ...

  • go语言基础

    go语言基础 go 语言接口

  • Go语言探索 - 12(结局)

    Go语言基础系列博客用到的所有示例代码 上一篇文章文章主要学习了Go语言中的接口、反射以及错误和异常处理。本篇文章...

  • Golang 学习笔记十四 反射

    参考《快学 Go 语言》第 15 课 —— 反射反射是 Go 语言学习的一个难点,但也是非常重要的一个知识点。反射...

  • go语言 反射

    为何需要反射? 下面例子试图打印出传入的interface值,无法找到无尽的未知类型的表示方式,我们被卡住了。这就...

  • go语言反射

    反射的特点 反射功能具有强大的功能 反射是用程序检查其所拥有的结构,尤其是类型的一种能力 是元编程的一种形式 我们...

  • Go语言反射

    【转】https://www.cnblogs.com/itbsl/p/10551880.html[https://...

网友评论

      本文标题:Go语言基础——反射

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