GoLong的学习之路(二十)进阶,语法之反射(reflect包)
这个是为了接上之前的语法篇的。按照我的学习计划,这里此时应该有一个小项目来做一个统合。但是吧,突然觉得,似乎也没必要。能学go的大部分肯定都是有其他语言的基础的。
接下来说反射
文章目录
- 反射介绍
- reflect包
- TypeOf
- type name和type kind
- type kind
- type name
- ValueOf
- 通过反射设置变量的值
- isNil()和isValid()
- 结构体反射
- StructField类型
- 例子
- 双刃剑
反射介绍
变量机制
Go语言中的变量是分为两部分的:
类型信息:预先定义好的元信息。值信息:程序运行过程中可动态变化的。
程序运行
反射是指在程序运行期间对程序本身进行访问和修改的能力。
程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。
在运行程序时,程序无法获取自身的信息。
解决这个问题
支持反射的语言可以在程序编译期间将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期间获取类型的反射信息,并且有能力修改它们。
Go程序在运行期间使用reflect包访问程序的反射信息.
reflect包
空接口可以存储任意类型的变量,那我们如何知道这个空接口保存的数据是什么呢?
反射就是在运行时动态的获取一个变量的类型信息和值信息。
在接口那一章说,任何接口值都由是一个具体类型和具体类型的值两部分组成的。而这个接口值是在Go语言的反射机制中。
在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。

TypeOf
在Go语言中,使用reflect.TypeOf()函数可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息
import ("fmt""reflect"
)func reflectType(x interface{}) {v := reflect.TypeOf(x)fmt.Printf("type:%v\n", v)
}
func main() {var a float32 = 3.14reflectType(a) // type:float32var b int64 = 100reflectType(b) // type:int64
}
type name和type kind
type kind
在反射中关于类型还划分为两种:类型(Type) 和 种类(Kind)
在Go语言中可以使用type关键字构造很多自定义类型,而种类(Kind)就是指底层的类型,但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)
type myInt int64func reflectType(x interface{}) {t := reflect.TypeOf(x)fmt.Printf("type:%v kind:%v\n", t.Name(), t.Kind())
}func main() {var a *float32 // 指针var b myInt // 自定义类型var c rune // 类型别名reflectType(a) // type: kind:ptrreflectType(b) // type:myInt kind:int64reflectType(c) // type:int32 kind:int32type person struct {name stringage int}type book struct{ title string }var d = person{name: "小王子",age: 18,}var e = book{title: "天气正好"}reflectType(d) // type:person kind:structreflectType(e) // type:book kind:struct
}
简单而言就是,我们需要函数名的时候用type,需要定义的指针还是结构体就用kind
type name
Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。
ValueOf
reflect.ValueOf()返回的是reflect.Value类型,其中包含了原始值的值信息。reflect.Value与原始值之间可以互相转换。
reflect.Value类型提供的获取原始值的方法:

func reflectValue(x interface{}) {v := reflect.ValueOf(x)k := v.Kind()switch k {case reflect.Int64:// v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换fmt.Printf("type is int64, value is %d\n", int64(v.Int()))case reflect.Float32:// v.Float()从反射中获取浮点型的原始值,然后通过float32()强制类型转换fmt.Printf("type is float32, value is %f\n", float32(v.Float()))case reflect.Float64:// v.Float()从反射中获取浮点型的原始值,然后通过float64()强制类型转换fmt.Printf("type is float64, value is %f\n", float64(v.Float()))}
}
func main() {var a float32 = 3.14var b int64 = 100reflectValue(a) // type is float32, value is 3.140000reflectValue(b) // type is int64, value is 100// 将int类型的原始值转换为reflect.Value类型c := reflect.ValueOf(10)fmt.Printf("type c :%T\n", c) // type c :reflect.Value
}
通过反射设置变量的值
在函数中通过反射修改变量的值,需要注意函数参数传递的是值拷贝,必须传递变量地址才能修改变量值。而反射中使用专有的Elem()方法来获取指针对应的值。
package mainimport ("fmt""reflect"
)func reflectSetValue1(x interface{}) {v := reflect.ValueOf(x)if v.Kind() == reflect.Int64 {v.SetInt(200) //修改的是副本,reflect包会引发panic}
}
func reflectSetValue2(x interface{}) {v := reflect.ValueOf(x)// 反射中使用 Elem()方法获取指针对应的值if v.Elem().Kind() == reflect.Int64 {v.Elem().SetInt(200)}
}
func main() {var a int64 = 100// reflectSetValue1(a) //panic: reflect: reflect.Value.SetInt using unaddressable valuereflectSetValue2(&a)fmt.Println(a)
}
isNil()和isValid()
isNil()
func (v Value) IsNil() bool
注意:IsNil()报告v持有的值是否为nil。v持有的值的分类必须是通道、函数、接口、映射、指针、切片之一;否则IsNil函数会导致panic。
isValid()
func (v Value) IsValid() bool
注意:IsValid()返回v是否持有一个值。如果v是Value零值会返回假,此时v除了IsValid、String、Kind之外的方法都会导致panic。
- IsNil()常被用于判断指针是否为空
- IsValid()常被用于判定返回值是否有效。
结构体反射
任意值通过reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.Type)的NumField()和Field()方法获得结构体成员的详细信息
reflect.Type中与获取结构体成员相关的的方法。

StructField类型
StructField类型用来描述结构体中的一个字段的信息
type StructField struct {// Name是字段的名字。PkgPath是非导出字段的包路径,对导出字段该字段为""。// Name stringPkgPath stringType Type // 字段的类型Tag StructTag // 字段的标签Offset uintptr // 字段在结构体中的字节偏移量Index []int // 用于Type.FieldByIndex时的索引切片Anonymous bool // 是否匿名字段
}
参见http://golang.org/ref/spec#Uniqueness_of_identifiers
例子
当我们使用反射得到一个结构体数据之后可以通过索引依次获取其字段信息,也可以通过字段名去获取指定的字段信息。
type student struct {Name string `json:"name"`Score int `json:"score"`
}func main() {stu1 := student{Name: "小王子",Score: 90,}t := reflect.TypeOf(stu1)fmt.Println(t.Name(), t.Kind()) // student struct// 通过for循环遍历结构体的所有字段信息for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))}// 通过字段名获取指定结构体字段信息if scoreField, ok := t.FieldByName("Score"); ok {fmt.Printf("name:%s index:%d type:%v json tag:%v\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json"))}
}
编写一个函数printMethod(s interface{})来遍历打印s包含的方法
/ 给student添加两个方法 Study和Sleep(注意首字母大写)
func (s student) Study() string {msg := "好好学习,天天向上。"fmt.Println(msg)return msg
}func (s student) Sleep() string {msg := "好好睡觉,快快长大。"fmt.Println(msg)return msg
}func printMethod(x interface{}) {t := reflect.TypeOf(x)v := reflect.ValueOf(x)fmt.Println(t.NumMethod())for i := 0; i < v.NumMethod(); i++ {methodType := v.Method(i).Type()fmt.Printf("method name:%s\n", t.Method(i).Name)fmt.Printf("method:%s\n", methodType)// 通过反射调用方法传递的参数必须是 []reflect.Value 类型var args = []reflect.Value{}v.Method(i).Call(args)}
}
双刃剑
反射是一个强大并富有表现力的工具,能让我们写出更灵活的代码。但是反射不应该被滥用,原因有以下三个。
- 基于反射的代码是极其脆弱的,反射中的类型错误会在真正运行的时候才会引发panic,那很可能是在代码写完的很长时间之后。
- 大量使用反射的代码通常难以理解。
- 反射的性能低下,基于反射实现的代码通常比正常代码运行速度慢一到两个数量级。
相关文章:
GoLong的学习之路(二十)进阶,语法之反射(reflect包)
这个是为了接上之前的语法篇的。按照我的学习计划,这里此时应该有一个小项目来做一个统合。但是吧,突然觉得,似乎也没必要。能学go的大部分肯定都是有其他语言的基础的。 接下来说反射 文章目录 反射介绍reflect包TypeOftype name和type kin…...
关于表单校验,:rules=“loginRules“
在写好validator相关的方法后,rule测试没有生效 <el-form ref"loginForm" :model"loginForm" :rules"loginRules" class"login-form" <el-form-item prop"username"> <el-input ref"usernam…...
统一消息分发中心设计
背景 我们核心业务中订单完成时,需要完成后续的连带业务,扣件库存库存、增加积分、通知商家等。 如下图的架构: 这样设计出来导致我们的核心业务和其他业务耦合,每次新增连带业务或者去掉连带业务都需要修改核心业务。 一方面&…...
前端项目导入vue和element
1.安装nodejs 下载链接https://cdn.npmmirror.com/binaries/node/v18.18.0/node-v18.18.0-x64.msi 进入cmd 命令行模式 管理员身份运行 输入 (node -v)能看到版本号 npm config set prefix "C:\Program Files\nodejs" 默认路径 npm config…...
【11】使用透视投影建立一个3D空间的测试
核心操作: 1.proj view model 这三个矩阵 glm::mat4 mvp m_Proj * m_View * model; m_Shader->Bind(); m_Shader->SetUniformMat4f("u_MVP", mvp);着色器里面就: proj:投影矩阵,可以选择正交投影,或者透视投影…...
【广州华锐互动】VR影视制片虚拟仿真教学系统
随着虚拟现实(VR)技术的不断发展,VR在影视制片教学中的应用场景也变得越来越丰富。本文将介绍VR在影视制片教学中的常见应用场景及其意义,并通过案例分析来更好地展示其应用前景。 在影视制片教学中,VR可以提供一种沉浸式的制作体验。其中&am…...
从研发域到量产域的自动驾驶工具链探索与实践
导读 本文整理自 2023 年 9 月 5 日百度云智大会 - 智能汽车分论坛,百度智能云自动驾驶云研发高级经理徐鹏的主题演讲《从研发域到量产域的自动驾驶工具链探索与实践》。 全文中部段落附有演讲中 2 个产品演示视频的完整版,精彩不容错过。 (视频观看&…...
404. 左叶子之和
原题链接:404. 左叶子之和 思路: 首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。 节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节…...
基于SSM的课程管理系统
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...
【hcie-cloud】【5】华为云Stack规划设计之华为云Stack标准化配置、缩略语【下】
文章目录 前言、华为云Stack交付综述为云Stack标准组网华为云Stack标准化配置华为云Stack配置概览华为云Stack云服务全视图华为云Stack部署方案节点类型说明华为云Stack云服务组件部署场景管理节点部署原则云平台管理规格华为云Stack IaaS场景&高阶场景起步必选部署组件x86…...
搭建自己的MQTT服务器,实现设备上云(Ubuntu+EMQX)
一、EMQX介绍 这篇文章教大家在ECS云服务器上部署EMQX,搭建自己私有的MQTT服务器,配置EMQX实现设备上云,设备数据转发,存储;服务器我采用的华为云的ECS服务器,系统选择Ubuntu系统。 Windows版本的看这里: https://blog.csdn.net/xiaolong1126626497/article/details/1…...
web3案例中解决交易所中 ETH与token都是0问题 并帮助确认展示是否成功
可能写了这么久 很多人会发现一个问 我们前面的案例 个人在交易所中的 自定义token 和 ETH 一直是放了个0 大家也不太敢确认是否真的有效 那么 很简单 我们操作 存入一些进交易所 不就ok了 我们 来看之前交易所写的代码 我们写了 depositEther 存入 ETH 和 depositToken 存入…...
unreal engine oculus 在vr场景中fade in , fade out
https://www.youtube.com/watch?vxRA7hRiXwuA...
0. 前言与大纲
机器学习面试题汇总与解析——前言与大纲 故事引入专栏介绍作者介绍大纲 受众:本教程适合于Python已经入门的学生或人士,有一定的编程基础。 本教程适合于算法工程师、机器学习求职的学生或人士。 故事引入 蒋 豆 芽:老李,我们…...
家乡特色饮食体验系统的设计与实现-计算机毕设 附源码 27533
家乡特色饮食体验系统的设计与实现 摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对家乡特色…...
本地数据库迁移到云端服务器
工具迁移xtrabackup 创建云服务器——通过云服务器提供的公网地址远程连接XShell——利用迁移工具将数据库从本地迁移到云服务器 (1)创建云服务器 (2)远程连接XShell (3)yum安装mysql (4&…...
SpringCloudGateway--Sentinel限流、熔断降级
目录 一、概览 二、安装Sentinel 三、微服务整合sentinel 四、限流 1、流控模式 ①直接 ②关联 ③链路 2、流控效果 ①快速失败 ②Warm Up ③排队等待 五、熔断降级 1、慢调用比例 2、异常比例 3、异常数 一、概览 SpringCloudGateway是一个基于SpringBoot2.x的…...
ARMday02(汇编语法、汇编指令)
汇编语法 汇编文件中的内容 1.伪操作:在汇编程序中不占用存储空间,但是可以在程序编译时起到引导和标识作用 .text .global .glbal .if .else .endif .data .word.... 2.汇编指令:每一条汇编指令都用来标识一个机器码,让计算机做…...
docker容器中运行jar 出现invalid or corrupt jarfile
1,背景: 在本地java开发完毕之后,想要打包成docker镜像,方便安装。由于本地没有docker环境,也懒得装了。有一台测试的linux机器可以使用,所以先在本地打包生成xxx.jar,然后拷贝到有docker环境的…...
PHP+MySQL人才招聘小程序系统源码 带完整前端+后端搭建教程
在当今竞争激烈的人才市场中,招聘平台的需求日益增长。传统的招聘平台往往需要投入大量的人力物力进行维护和管理,这对于许多中小企业来说是一个沉重的负担。因此,开发一个简单易用、高效便捷的招聘平台显得尤为重要。 PHP是一种流行的服务器…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
