前面我们在学习到struct结构体的时候,因为结构体中的字段首字母大写,而我们想把json文件映射到该结构体上时,需要在在结构体字段后面加上json标签,表明结构体字段和json字段的映射关系。这其中就用到了反射的方式去获取标签,取出该标签对应的json字段然后存储到结构体字段上。

Go语言中提供了反射的包为reflect。在 reflect 包中,主要通过两个函数TypeOf()ValueOf()实现反射,TypeOf()获取到的结果是reflect.Type 类型,ValueOf()获取到的结果是reflect.Value类型。

1. 理解反射的类型(Type)

reflect.TypeOf()返回的是Type类型,Type中包含了一个对象会有的相关信息,对象名,对象类型,对象的方法,对象中的属性等等。

reflect.Type中的方法:

// 通用方法

func (t *rtype) String() string // 获取 t 类型的字符串描述,不要通过 String 来判断两种类型是否一致。

func (t *rtype) Name() string // 获取 t 类型在其包中定义的名称,未命名类型则返回空字符串。

func (t *rtype) PkgPath() string // 获取 t 类型所在包的名称,未命名类型则返回空字符串。

func (t *rtype) Kind() reflect.Kind // 获取 t 类型的类别。

func (t *rtype) Size() uintptr // 获取 t 类型的值在分配内存时的大小,功能和 unsafe.SizeOf 一样。

func (t *rtype) Align() int  // 获取 t 类型的值在分配内存时的字节对齐值。

func (t *rtype) FieldAlign() int  // 获取 t 类型的值作为结构体字段时的字节对齐值。

func (t *rtype) NumMethod() int  // 获取 t 类型的方法数量。

func (t *rtype) NumField() int //返回一个struct 类型 的属性个数,如果非struct类型会抛异常

func (t *rtype) Method() reflect.Method  // 根据索引获取 t 类型的方法,如果方法不存在,则 panic。
// 如果 t 是一个实际的类型,则返回值的 Type 和 Func 字段会列出接收者。
// 如果 t 只是一个接口,则返回值的 Type 不列出接收者,Func 为空值。 func (t *rtype) MethodByName(string) (reflect.Method, bool) // 根据名称获取 t 类型的方法。 func (t *rtype) Implements(u reflect.Type) bool // 判断 t 类型是否实现了 u 接口。 func (t *rtype) ConvertibleTo(u reflect.Type) bool // 判断 t 类型的值可否转换为 u 类型。 func (t *rtype) AssignableTo(u reflect.Type) bool // 判断 t 类型的值可否赋值给 u 类型。 func (t *rtype) Comparable() bool // 判断 t 类型的值可否进行比较操作
//注意对于:数组、切片、映射、通道、指针、接口
func (t *rtype) Elem() reflect.Type // 获取元素类型、获取指针所指对象类型,获取接口的动态类型

有个方法是Elem(),获取元素类型、获取指针所指对象类型,获取接口的动态类型。对指针类型进行反射的时候,可以通过reflect.Elem()获取这个指针指向元素的类型。

package main

import (
"fmt"
"reflect"
"strconv"
) type User struct {
Name string
Age int
} func (User) GetUser(user User) string{
return user.Name + " " + strconv.Itoa(user.Age)
} func main() {
user := &User{"xiaoming", 13}
of := reflect.TypeOf(user)
elem := reflect.TypeOf(user).Elem()
fmt.Println(of.Kind(),of.Name())
fmt.Println(elem.Kind(),elem.Name())
} 结果:
ptr
struct User

从上面的结果来看,TypeOf(user)的种类为ptr,Go中反射对所有的指针变量的种类都是ptr,但是指针变量的类型名称是空的。

通过Elem()方法可以得到指针指向的元素的类型和名称,得到User的类型为struct,名称为User。

1.1 通过反射获取结构体成员类型
package main

import (
"fmt"
"reflect"
"strconv"
) type User struct {
Name string
Age int
} func (User) GetUser(user User) string{
return user.Name + " " + strconv.Itoa(user.Age)
} func main() {
user := User{"xiaoming", 13} //反射获取对象类型,字段类型
userType := reflect.TypeOf(user)
fmt.Println(userType.Name(),userType.Kind()) for i := 0; i < userType.NumField(); i++ {
fieldType := userType.Field(i)
fmt.Printf("name: %v tag: '%v'\n", fieldType.Name, fieldType.Tag)
} if name, ok := userType.FieldByName("Name"); ok {
fmt.Println(name)
}
} 输出信息:
User struct
name: Name tag: ''
name: Age tag: ''
{Name string 0 [0] false}

在上面的代码中,NumField()方法获取结构体类型中的属性个数,通过Field(i)方法来获取结构体中的属性,返回的是StructField类型的结构体。该对象中包含如下信息:

type StructField struct {
Name string // 字段名
PkgPath string // 字段路径
Type Type // 字段反射类型对象
Tag StructTag // 字段的结构体标签
Offset uintptr // 字段在结构体中的相对偏移
Index []int // Type.FieldByIndex中的返回的索引值
Anonymous bool // 是否为匿名字段
}

可以看到有我们关注的字段名,字段类型,还有tag类型等等。

2. 通过反射获取对象值

获取对象值通过ValueOf()方法来实现。

package main

import (
"fmt"
"reflect"
"strconv"
) type User struct {
Name string
Age int
} func (User) GetUser(user User) string{
return user.Name + " " + strconv.Itoa(user.Age)
} func main() {
user := User{"xiaoming", 13} //反射获取对象值
elem := reflect.ValueOf(user)
fmt.Println(elem)
for i := 0; i < elem.NumField(); i++ {
field := elem.Field(i)
i2 := field.Type()
fmt.Println(i2.Name(), " ", field)
}
} 输出:
{xiaoming 13}
string xiaoming
int 13
2.1 创建对象和调用方法
package main

import (
"fmt"
"reflect"
"strconv"
) type User struct {
Name string
Age int
} func (User) GetUser(user User) string{
return user.Name + " " + strconv.Itoa(user.Age)
} func main() {
user1 := User{"xiaoming", 13}
user := User{} //反射获取对象值
elem := reflect.TypeOf(user)
//创建一个实例
value:= reflect.New(elem).Elem()
value.Field(0).SetString("xiaohong")
value.Field(1).SetInt(15) fmt.Println(value.Field(0),value.Field(1)) of := reflect.ValueOf(user)
params := make([]reflect.Value,1)
params[0] = reflect.ValueOf(user1)
//调用方法,传递参数
call := of.Method(0).Call(params)
fmt.Println(call)
} 输出: xiaohong 15
[xiaoming 13]

Go中的反射reflect的更多相关文章

  1. golang中的反射reflect详解

    先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...

  2. go语言中的反射reflect

    package main; import ( "fmt" "reflect" ) //反射refection //反射使用TypeOf和ValueOf函数从接口 ...

  3. Java中的反射--Reflect

    在张孝祥老师的Java讲解中,学习到了Java反射的一部分知识,觉得有必要好好学习一下哈. 一.反射的理解 经典总结:反射就是把Java类中的各种成分映射成为相应的Java类 例如:一个Java类中用 ...

  4. Java中的反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  5. Go 中的反射要点

    简介 反射是元数据编程的一种形式,指的是程序获得本身结构的一种能力.不同语言的反射模型实现不一样,本文中的反射,仅仅指的是Go语言中的反射模型. 类型以及接口 这个基本概念需要清晰,这里不详细展开. ...

  6. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

  7. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  8. Android中Java反射技术的使用示例

    import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Metho ...

  9. 【转】JAVA中的反射机制

    反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本 ...

随机推荐

  1. mysql重复数据下,删除一条重复数据

    delete from information where id in (select id from (select max(id) as id,count(*) as ccc from infor ...

  2. POI 身份证号码 手机号 日期值的处理方式

    private static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ...

  3. 【深入浅出-JVM】(3):浮点数

    -5 浮点数推导 二进制转十进制 1 10000001 01000000000000000000000 1 10000001 101000000000000000000000 如果指数位不全为 0 则 ...

  4. Java学习笔记之---类和对象

    Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态  例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...

  5. vue-cli · Failed to download repo vuejs-templates/webpack: self signed certificate in certificate chain

    vue init webpack <Project name> 报错: vue-cli · Failed to download repo vuejs-templates/webpack: ...

  6. 用Supervisor实现进程守护,在异常退出时自动重启

    程序启动后,有些是以daemon的形式运行,但在意外退出后,如果不能及时重新启动,会有比较严重的影响. 比如Zimg在图片处理中由于某些图片处理失败,会导致zimg进程挂掉,影响正常的服务提供,并且只 ...

  7. 每周一个js重要概念之一 调用堆栈

    js写了也有两年多了,大到复杂的后台系统,小到页面,还有日均300万的网页主站,HTML5的适配页面等等. 框架也杂七杂八接触了不少,从小的jquery.bootstrap.echarts等等,到大一 ...

  8. MyBatis从入门到精通:第一章配置MyBatis

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  9. java面试题库(长期)

    本文内容来自互联网各种面试实例,以及自己的面试经历,主要是中级开发的面试题 初中级java面试主要分为几个部分: 0.序 1.java基础 2. java多线程 3. jvm知识 4. spring等 ...

  10. svg文字描边动画

    svg动画在网页中是经常见到的,svg动画使得网页看起来清新美观 任何不规则图形都可以由svg绘制完成,当然也包括文字,文字本身就可以看作一个不规则图形