前面我们在学习到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. LightOJ 1422:Halloween Costumes(区间DP入门)

    http://lightoj.com/volume_showproblem.php?problem=1422 题意:去参加派对,有n场派对,每场派对要穿第wi种衣服,可以选择外面套一件,也可以选择脱掉 ...

  2. jdk源码--LinkedList

    本文基于jdk1.8_171 LinkedList介绍 之前看了ArrayList,内部是一个数组.这次看了LinkedList,作用和ArrayList一样,但是内部是链表形式.链表结构如下图: 数 ...

  3. 基于SpringBoot的Web API快速开发基础框架

    其实还是很因为懒,才会有这个案例项目的产生,每次开启一个终端的小服务都要整理一次框架,造成重复的.不必要的.缺乏创造性的劳动,SO,本着可以用.用着简单的原则上传代码到Github,希望有需要的朋友直 ...

  4. Jenkins高级应用——Publish Over SSH插件

    在之前的篇幅中有介绍,利用jenkins结合shell脚本完成远程部署的功能,点击Jenkins结合shell+expect脚本完成线上环境自动构建部署即可查看. 上述方式需要引入expect脚本,安 ...

  5. 小白教程 Java web maven项目Windows下部署阿里云服务器全过程(买服务器,打包项目,连接服务器,配置服务器,部署项目)

    -------------首先:购买服务器---------------- Step1: 在https://www.aliyun.com/?utm_content=se_1043015注册登录阿里云 ...

  6. 洛谷P2265 路边的水沟

    题目 题目背景 LYQ市有一个巨大的水沟网络,可以近似看成一个n*m的矩形网格,网格的每个格点都安装了闸门,我们将从水沟网络右下角的闸门到左上角的闸门的一条路径称为水流. 题目描述 现给定水沟网的长和 ...

  7. 个人永久性免费-Excel催化剂功能第95波-地图数据挖宝之IP地址转地理地址及不同经纬度版本转换

    经过上一波POI兴趣点查询后,地图数据挖宝也接近尾声,这次介绍在数据采集.准备过程中需要用到的一些转换功能,有IP地址转换地理地址及不同地图版本的经纬度转换. 背景知识 在电商.网络的数据分析过程中, ...

  8. [leetcode] 51. N-Queens (递归)

    递归,经典的八皇后问题. 利用一位数组存储棋盘状态,索引表示行,值为-1表示空,否则表示列数. 对行进行搜索,对每一行的不同列数进行判断,如果可以摆放符合规则,则摆放,同时遍历下一行. 遍历过程中,若 ...

  9. [leetcode] 62 Unique Paths (Medium)

    原题链接 字母题 : unique paths Ⅱ 思路: dp[i][j]保存走到第i,j格共有几种走法. 因为只能走→或者↓,所以边界条件dp[0][j]+=dp[0][j-1] 同时容易得出递推 ...

  10. 浅谈hosts文件

    1.什么是hosts文件?这个文件在哪? hosts文件(域名解析文件)是将主机名映射到IP地址的一个纯文本文件,原始名称是HOSTS.TXT(IP,Internet Protocol,Interne ...