前面我们在学习到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. 并发编程-concurrent指南-回环栅栏CyclicBarrier

    字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行. java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步 ...

  2. 常用的方法论-5why

  3. 【Mysql】索引简介

    本文口味:番茄炒蛋,预计阅读:10分钟. 博客又停更了两个月,在这期间,对人生和世界多了许多思考.在人生的不同阶段,会对生活和世界有着不一样的认知,而认知的改变也会直接反应在行为模式之中. 对于生活的 ...

  4. S7 300数据块中的变量指定断电保持特性

    利用DB块内变量属性的保持性,勾选上就可以保持了.300PLC数据块默认断电保持.

  5. kuangbin专题 专题一 简单搜索 Fire Game FZU - 2150

    题目链接:https://vjudge.net/problem/FZU-2150 题意:’ . '代表火无法烧着的地方,‘ # ’表示草,火可以烧着.选择任意两个‘ # ’(可以两个都选同一个 ‘ # ...

  6. mysql查询语句出现sending data耗时解决

    在执行一个简单的sql查询,表中数据量为14万 sql语句为:SELECT id,titile,published_at from spider_36kr_record where is_analyz ...

  7. 3. Django每日一码 之 Serializers 源码

    2019-7-6 今日源码:rest-framework 序列化Serializers 序列化组件Serializers 源码分析 首先,它需要 data .many . instance,其中 in ...

  8. 新手上路——it人如何保持竞争力

    新手上路——如何保持竞争力 JINGZHENGLI 套用葛大爷的一句名言:21世纪什么最贵,人才.哪你是人才还是人材?还是人财或人裁?相信大家都不是最后一种.何如保持住这个光环呢?就需要我们保持我们独 ...

  9. Apache struts2远程命令执行_CVE-2017-9805(S2-052)漏洞复现

    Apache struts2远程命令执行_CVE-2017-9805(S2-052)漏洞复现 一.漏洞概述 Apache Struts2的REST插件存在远程代码执行的高危漏洞,Struts2 RES ...

  10. 一篇文章学会Docker命令

    目录 简介 镜像仓库 login pull push search 本地镜像管理 images rmi tag build history save load import 容器操作 ps inspe ...