Go反射指南

概念:

官方对此有个非常简明的介绍,两句话耐人寻味:

  1. 反射提供一种让程序检查自身结构的能力
  2. 反射是困惑的源泉

第1条,再精确点的描述是“反射是一种检查interface变量的底层类型和值的机制”。 第2条,很有喜感的自嘲,不过往后看就笑不出来了,因为你很可能产生困惑。

reflect 实现了运行时的反射能力,能够让程序操作不同类型的对象。反射包中有两对非常重要的函数和类型,两个函数分别是:

  • reflect.TypeOf()   能获取类型信息;
  • reflect.ValueOf() 能获取数据的运行时表示;

只有这么简单吗?当然不是,请继续阅读。

引出:

其实了解反射的第一步,应从interface入手,因为反射与接口存在着千丝万缕的关系。

如下是一段interface的源码

type iface struct {tab  *itabdata unsafe.Pointer
}// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {inter  *interfacetype_type  *_typelink   *itabbad    int32inhash int32      // has this itab been added to hash?fun    [1]uintptr // variable sized
}

看不懂也没关系,我对其大致简化一番,从reflect角度再来看看,并思考从iface中看到的字段:

type I interface{// 方法集
}
type iface struct{typ reflect.Type   // 储存类型信息val reflect.Value  // 储存实际值
}

之所以引出interface,是因为想说interface类型有个(value,type)对,而反射就是检查interface的这个(value, type)对的。具体一点说就是Go提供一组方法提取interface的value,提供另一组方法提取interface的type。

  • reflect.Type 提供一组接口处理interface的类型,即(value, type)中的type
  • reflect.Value 提供一组接口处理interface的值,即(value, type)中的value

下面会提到反射对象,所谓反射对象即反射包里提供的两种类型的对象。

  • reflect.Type 类型对象
  • reflect.Value 类型对象

三大法则:

第一法则:

interface{} 变量,可以反射出反射对象;

下面示例,看看是如何通过反射获取一个变量的值和类型的:

package mainimport ("fmt""reflect"
)func main() {var x float64 = 3.4t := reflect.TypeOf(x)  //t is reflext.Typefmt.Println("type:", t)v := reflect.ValueOf(x) //v is reflext.Valuefmt.Println("value:", v)
}运行如下:
type: float64
value: 3.4
是不是疑惑了,明明是上述是x->reflect类型,却依然说是 interface{} --变为--> reflect类型呢?这是因为,在TypeOf 与 ValueOf 内部,自动将 值类型,转化为了 接口类型。

 

第二法则:

从反射对象可以获取 interface{} 变量;

package mainimport ("fmt""reflect"
)func main() {var x float64 = 3.4v := reflect.ValueOf(x) //v is reflext.Valuevar y float64 = v.Interface().(float64)fmt.Println("value:", y)
}

1、用reflect.ValueOf(x) 获取,value值。

2、v.Interface() 转化成接口。

3、类型断言转化成,对应的基本类型

 

第三法则:

要修改反射对象,其值必须可设置。

通过反射可以将interface类型变量转换成反射对象,可以使用该反射对象设置其持有的值。在介绍何谓反射对象可修改前,先看一下失败的例子:

package mainimport ("reflect"
)func main() {var x float64 = 3.4v := reflect.ValueOf(x)v.SetFloat(7.1) // Error: will panic.
}如下代码,通过反射对象v设置新值,会出现panic。报错如下:panic: reflect: reflect.Value.SetFloat using unaddressable value

错误原因即是v是不可修改的。

反射对象失败,取决于是否可以修改其储存的值。回想一下函数传参时,是传值还是传址,就不难理解上例中为何失败。

上例中,传入 reflect.ValueOf() 函数的其实是x的值,而非x本身。即通过v修改其值是无法影响x的,也即是无效的修改,所以 golang 会报错。

想到此处,即可明白,如果构建v时使用x的地址就可实现修改了,但此时v代表的是指针地址,我们要设置的是指针所指向的内容,也即我们想要修改的是*v。 那怎么通过v修改x的值呢?

reflect.Value 提供了 Elem() 方法,可以获得指针向指向的Value 。看如下代码:

package mainimport (
"reflect""fmt"
)func main() {var x float64 = 3.4v := reflect.ValueOf(&x)v.Elem().SetFloat(7.1)fmt.Println("x :", v.Elem().Interface())
}

1、调用reflect.ValueOf 获取变量指针。

2、调用 reflect.Value.Elem 获取指针指向的变量。

3、调用 reflect.Value.SetFloat() 更新变量。

总结:

以上为本篇博客精华内容,如有不妥,请及时私信联系我,斟酌之后必加以纠正。

待后续深入学习时,会转回继续修改。

参考内容:

1、《Go专家编程》

2、《Go语言设计与实践》

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9790.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Django的个人博客系统的设计与实现

【Django】基于Django的个人博客系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 系统采用Python作为主要开发语言,结合Django框架构建后端逻辑,并运用J…

Vue-day2

7.Vue的生命周期 mounted函数:在页面加载完毕时,发送异步请求,加载数据,渲染页面 createApp({date(){},methods:{},mounted:function(){console.log(Vue挂载完毕,发送请求获取数据)} }).mount(#{app}) 8.ajax函数库…

SSM-MyBatis-总结

文章目录 一、Hello MyBatis1.1 流程1.2 总结 二、Crud 的一些注意点三、参数传递3.1 #{ } VS ${ }3.2 单、复参数传递(1)单参数(2)多参数 -- Param(3)总结 四、查询结果返回--结果封装4.1 ResultType 一般…

全面解析文件上传下载删除漏洞:风险与应对

在数字化转型的时代,文件上传、下载与删除功能已经成为各类应用程序的标准配置,从日常办公使用的协同平台,到云端存储服务,再到社交网络应用,这些功能在给用户带来便捷体验、显著提升工作效率的同时,也隐藏…

GSI快速收录服务:让你的网站内容“上架”谷歌

辛苦制作的内容无法被谷歌抓取和展示,导致访客无法找到你的网站,这是会让人丧失信心的事情。GSI快速收录服务就是为了解决这种问题而存在的。无论是新上线的页面,还是长期未被收录的内容,通过我们的技术支持,都能迅速被…

JavaScript

书写位置 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>/*C…

Go的内存逃逸

Go的内存逃逸 内存逃逸是 Go 语言中一个重要的概念&#xff0c;指的是本应分配在栈上的变量被分配到了堆上。栈上的变量在函数结束后会自动回收&#xff0c;而堆上的变量需要通过垃圾回收&#xff08;GC&#xff09;来管理&#xff0c;因此内存逃逸会增加 GC 的压力&#xff0…

python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。 按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位异或运算&#xff1a; 两个等长度二进制数上下对齐&#xff0c;相…

图论——最小生成树的扩展应用

最小生成树相关原理 acwing1146.新的开始 假设存在一个“超级发电站” 在每一个矿井修发电站相当于从这个“超级发电站”到各个矿井连一条长度为 v [ i ] v[i] v[i]的边。 这样一来这就是一个最短路的模板题。 #include <iostream> #include <cstring> using na…

供应链系统设计-供应链中台系统设计(十)- 清结算中心概念片篇

综述 我们之前在供应链系统设计-中台系统设计系列&#xff08;五&#xff09;- 供应链中台实践概述文章中针对中台到底是什么进行了描述&#xff0c;对于中台的范围也进行划分&#xff0c;如下图所示&#xff1a; 关于商品中心&#xff0c;我们之前用4篇文章介绍了什么是商品中…

Git图形化工具【lazygit】

简要介绍一下偶然发现的Git图形化工具——「lazygit」 概述 Lazygit 是一个用 Go 语言编写的 Git 命令行界面&#xff08;TUI&#xff09;工具&#xff0c;它让 Git 操作变得更加直观和高效。 Github地址&#xff1a;https://github.com/jesseduffield/lazygit 主要特点 主要…

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…

全程Kali linux---CTFshow misc入门(14-24)

第十四题&#xff1a; dd命令&#xff1a;dd是一个用于复制和转换数据的命令&#xff0c;它可以对文件、设备等进行操作&#xff0c;在数据备份、转换格式等场景经常使用。 ifmisc14.jpg&#xff1a;if表示 “input file”&#xff08;输入文件&#xff09;&#xff0c;这里指…

网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开。

一、前言 我从24年11月份开始学习网络爬虫应用开发&#xff0c;经过2个来月的努力&#xff0c;于1月下旬完成了开发一款网络爬虫软件的学习目标。这里对本次学习及应用开发进行一下回顾总结。 前几天我已经发了一篇日志&#xff08;网络爬虫学习&#xff1a;应用selenium从搜…

C语言连接Mysql

目录 C语言连接Mysql下载 mysql 开发库 方法介绍mysql_init()mysql_real_connect()mysql_query()mysql_store_result()mysql_num_fields()mysql_fetch_fields()mysql_fetch_row()mysql_free_result()mysql_close() 完整代码 C语言连接Mysql 下载 mysql 开发库 方法一&#xf…

前端-Rollup

Rollup 是一个用于 JavaScript 的模块打包工具&#xff0c;它将小的代码片段编译成更大、更复杂的代码&#xff0c;例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式&#xff0c;而不是以前的 CommonJS 和 AMD 等特殊解决方案。ES 模块允许你自由…

Ubuntu20.04 磁盘空间扩展教程

Ubuntu20.04 磁盘空间扩展教程_ubuntu20 gpart扩容-CSDN博客文章浏览阅读2w次&#xff0c;点赞38次&#xff0c;收藏119次。执行命令查看系统容量相关的数据&#xff1a;df -h当前容量为20G&#xff0c;已用18G&#xff08;96%&#xff09;&#xff0c;可用844M&#xff0c;可用…

使用Ollama本地部署DeepSeek R1

前言 DeepSeek是一款开源的智能搜索引擎&#xff0c;能够通过深度学习技术提高搜索的智能化水平。如果你正在寻找一种方式来将DeepSeek部署在本地环境中&#xff0c;Ollama是一个非常方便的工具&#xff0c;它允许你在本地快速部署并管理各种基于AI的模型。 在本篇博客中&…

数据结构选讲 (更新中)

参考 smWCDay7 数据结构选讲2 by yyc 。 可能会补充的&#xff1a; AT_cf17_final_j TreeMST 的 F2 Boruvka算法 目录 AT_cf17_final_j Tree MSTP5280 [ZJOI2019] 线段树 AT_cf17_final_j Tree MST link 题意 给定一棵 n n n 个点的树&#xff0c;点有点权 w i w_i wi​&am…

Redis学习之哨兵二

一、API 1.sentinel masters:展示被监控的主节点状态及相关的统计信息 2.sentinel master <master name>:展示指定的主节点的状态以及相关的统计信息 3.sentinel slaves <master name>:展示指定主节点的从节点状态以及相关的统计信息 4.sentinel sentinels <mas…