前面我们在学习到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. .NET分布式框架 | Orleans 知多少

    引言 公司物联网项目集成Orleans以支持高并发的分布式业务,对于Orleans也是第一次接触,本文就分享下个人对Orleans的理解. 这里先抛出自己的观点:Orleans 是一个支持有状态云生应 ...

  2. HTTP 学习笔记03

    通用信息头 Cache-Control : no-cache(不缓存当前请求) [*] Connection:close(返回当前请求后立即断开)[*] Date:...(HTTP消息产生的时间) P ...

  3. Codeforces Gym101170I:Iron and Coal(建多幅图+多次BFS)***

    题目链接 题意 有n个点,其中有m个点是铁矿,k个点是煤,从1号点出发,你可以派一些士兵跑向不同的点,问占领至少一个铁矿和一个煤的时候,最少需要占领多少个点. 思路 建两幅图,其中一幅是正向边,一幅是 ...

  4. 分享常见的HTTP状态码

    本内容摘抄自RUNOOB.COM 当浏览一个网页时,浏览器会向网页所在服务器发出请求.当浏览器确定接收并显示网页之前,此网页所在的服务器会返回一个含有HTTP状态码(HTTP Status Code) ...

  5. c++学习书籍推荐《C++ Primer(中文版)(第5版)》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <C++ Primer(中文版)(第5版)>编辑推荐:一书在手,架构无忧:三十位一线架构师真知实践:百位架构师献计献策:十万文字尽显架构精华. 媒 ...

  6. Linux关闭进程。

    一.shell命令根据端口后关闭指定进程. $(netstat -nlp | | awk '{print $7}' | awk -F"/" '{ print $1 }') nets ...

  7. android_activity_研究(二)

    这次开始玩玩活动的生命周期.废话不说,先搞个小应用,大体思路是:主界面有两个按钮,一个按钮按下后,出现第二个界面:另一个按钮按下后,出现第三个界面,真他妈简单. 一.主界面: 1. 主界面布局xml文 ...

  8. youku_androidid

    youku_androidid = 1310; imei screenwidth screenhight

  9. backbone之路由锚点的替换

    1.需求 由于项目一开始做的时候不甚完善,所有的网页没有路由功能,导致一些搜索结果在页面跳转之后,没有被记录下来,在页面跳转之后回退,得到的是页面最原始的结果,没有指定的搜索条件.最近项目的在完善这些 ...

  10. Git命令行之快速入门

    从头开始创建一个版本库,添加一些内容,然后管理一些修订版本. 有两种建立 Git版本库 的基础技术.第一:从头开始创建,用现有的内容填充它.第二:可以克隆一个已有的版本库.这里选择从一个空的版本库开始 ...