广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Go反射底层原理及数据结构解析
  • 411
分享到

Go反射底层原理及数据结构解析

2024-04-02 19:04:59 411人浏览 安东尼
摘要

目录1. 反射的引入与介绍2. 反射的数据结构3. 如何通过反射对象来修改原数据对象的值?1. 反射的引入与介绍 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访

1. 反射的引入与介绍

在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

需要反射的 2 个常见场景:

  • 有时你需要编写一个函数,但是并不知道传给你的参数类型是什么,可能是没约定好;也可能是传入的类型很多,这些类型并不能统一表示。这时反射就会用的上了。
  • 有时候需要根据某些条件决定调用哪个函数,比如根据用户的输入来决定。这时就需要对函数和函数的参数进行反射,在运行期间动态地执行函数。

Java中动态代理与aop的实现,就要借助这种操作。而对于我们Go语言来说,也提供了反射的机制。

有了前面对于interface{}底层数据结构的了解,Go中的每个实例对象可以分为两快,类型信息与数值信息。而我们Go中提供的反射机制,能分别拿到这两块信息。

image.png

数据interface中保存有结构数据,拿到该数据对应的内存地址,然后把该数据转成interface,通过查看interface中的类型结构,就可以知道该数据的结构了,其实以上就是Go反射通俗的原理。

image.png

2. 反射的数据结构

type Type interface {
    // 所有的类型都可以调用下面这些函数
	// 此类型的变量对齐后所占用的字节数
	Align() int
	// 如果是 struct 的字段,对齐后占用的字节数
	FieldAlign() int
	// 返回类型方法集里的第 `i` (传入的参数)个方法
	Method(int) Method
	// 通过名称获取方法
	MethodByName(string) (Method, bool)
	// 获取类型方法集里导出的方法个数
	NumMethod() int
	// 类型名称
	Name() string
	// 返回类型所在的路径,如:encoding/base64
	PkgPath() string
	// 返回类型的大小,和 unsafe.Sizeof 功能类似
	Size() uintptr
	// 返回类型的字符串表示形式
	String() string
	// 返回类型的类型值
	Kind() Kind
	// 类型是否实现了接口 u
	Implements(u Type) bool
	// 是否可以赋值给 u
	AssignableTo(u Type) bool
	// 是否可以类型转换成 u
	ConvertibleTo(u Type) bool
	// 类型是否可以比较
	Comparable() bool
	// 下面这些函数只有特定类型可以调用
	// 如:Key, Elem 两个方法就只能是 Map 类型才能调用
	// 类型所占据的位数
	Bits() int
	// 返回通道的方向,只能是 chan 类型调用
	ChanDir() ChanDir
	// 返回类型是否是可变参数,只能是 func 类型调用
	// 比如 t 是类型 func(x int, y ... float64)
	// 那么 t.IsVariadic() == true
	IsVariadic() bool
	// 返回内部子元素类型,只能由类型 Array, Chan, Map, Ptr, or Slice 调用
	Elem() Type
	// 返回结构体类型的第 i 个字段,只能是结构体类型调用
	// 如果 i 超过了总字段数,就会 panic
	Field(i int) StructField
	// 返回嵌套的结构体的字段
	FieldByIndex(index []int) StructField
	// 通过字段名称获取字段
	FieldByName(name string) (StructField, bool)
	// FieldByNameFunc returns the struct field with a name
	// 返回名称符合 func 函数的字段
	FieldByNameFunc(match func(string) bool) (StructField, bool)
	// 获取函数类型的第 i 个参数的类型
	In(i int) Type
	// 返回 map 的 key 类型,只能由类型 map 调用
	Key() Type
	// 返回 Array 的长度,只能由类型 Array 调用
	Len() int
	// 返回类型字段的数量,只能由类型 Struct 调用
	NumField() int
	// 返回函数类型的输入参数个数
	NumIn() int
	// 返回函数类型的返回值个数
	NumOut() int
	// 返回函数类型的第 i 个值的类型
	Out(i int) Type
        // 返回类型结构体的相同部分
	common() *rtype
	// 返回类型结构体的不同部分
	uncommon() *uncommonType
}
type Value struct {
    typ *rtype
    ptr unsafe.Pointer
    flag
}

反射的实现和interface的组成很相似,都是由“类型”和“数据值”构成,但是值得注意的是:interface的“类型”和“数据值”是在“一起的”,而反射的“类型”和“数据值”是分开的。

TypeValue提供了非常多的方法:例如获取对象的属性列表、获取和修改某个属性的值、对象所属结构体的名字、对象的底层类型(underlying type)等等

Go中的反射,在使用中最核心的就两个函数:

  • reflect.TypeOf(x)
  • reflect.ValueOf(x)

这两个函数可以分别将给定的数据对象转化为以上的TypeValue。这两个都叫做反射对象

3. 如何通过反射对象来修改原数据对象的值?

在Go中,任何函数的参数都是值的拷贝,而非原数据。

反射函数reflect.ValueOf()也不例外。我们目前得到的反射对象,都是原对象的copy的反射对象,而非原对象本身,所以不可以修改到原对象.

那如何修改呢?

首先,在Go中要想让函数“有副作用“,传值必须传指针类型的。

var x float64 = 5.7
v := reflect.ValueOf(&x)

时还不行,因为这样反射对象对应的是原数据对象的指针类型,必须要拿到当前类型的值类型(*v)。 Go提供了另外一个方法Elem()

p := v.Elem()
fmt.Println(p.CanSet()) // true

p.SetFloat(6.6)
fmt.Println(x) // 6.6

经过以上操作,就可以修改原数据了,完整过程如下:

var x float64 = 5.7
v := reflect.ValueOf(&x)
p := v.Elem()
fmt.Println(p.CanSet()) // true
p.SetFloat(6.6)
fmt.Println(x) // 6.6

到此这篇关于Go反射底层原理及数据结构解析的文章就介绍到这了,更多相关 Go反射原理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Go反射底层原理及数据结构解析

本文链接: https://www.lsjlt.com/news/150847.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go反射底层原理及数据结构解析
    目录1. 反射的引入与介绍2. 反射的数据结构3. 如何通过反射对象来修改原数据对象的值?1. 反射的引入与介绍 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访...
    99+
    2022-11-13
  • Redis数据结构SortedSet的底层原理解析
    目录概述一些常用命令实现跳跃表跳表的插入压缩列表概述 一些常用命令 存储:zadd key score value获取:zrange key start end获取:同时获取分数:zrange key start end...
    99+
    2022-07-13
    Redis数据结构底层原理 SortedSet底层原理 Redis数据结构SortedSet
  • 分布式架构Redis中有哪些数据结构及底层实现原理
    目录引言1、面试官:我看你提到,项目中使用了Reids作为缓存,为什么是Reids而不是其他,Redis有什么优势吗?2、面试官:刚刚你提到Redis是单线程,为什么单线程模型的 R...
    99+
    2022-11-13
  • MySQL索引底层数据结构怎么理解
    这篇文章主要介绍“MySQL索引底层数据结构怎么理解”,在日常操作中,相信很多人在MySQL索引底层数据结构怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL索引底层数据结构怎么理解”的疑惑有所...
    99+
    2023-06-25
  • java中hashmap的底层数据结构与实现原理
    目录Hash结构HashMap实现原理为何HashMap的数组长度一定是2的次幂?重写equals方法需同时重写hashCode方法总结Hash结构 HashMap根据名称可知,其实...
    99+
    2022-11-12
  • C语言数据结构之vector底层实现机制解析
    目录一、vector底层实现机制刨析二、vector的核心框架接口的模拟实现1.vector的迭代器实现2.reserve()扩容3.尾插尾删(push_back(),pop_bac...
    99+
    2022-11-12
  • ThreadLocal数据存储结构原理解析
    目录一:简述二:TheadLocal的原理分析1.ThreadLocal的存储结构2.源码分析set()方法三:源码分析createMap()源码:流程图:expungeStaleE...
    99+
    2022-11-13
  • Redis做数据持久化的解决方案及底层原理
    目录数据持久化RDB生成方法savebgsave优点缺点AOFAOF记录过程ServerCron作用server.hz写入策略End之前的文章介绍了Redis的简单数据结构的相关使用...
    99+
    2022-11-12
  • go数据结构和算法BitMap原理及实现示例
    目录1. BitMap介绍如何判断数字在bit数组的位置设置数据到bit数组从bit数组中清除数据数字是否在bit数组中2. Go语言位运算左移右移使用&^和位移运算来给某一...
    99+
    2022-11-13
  • Redis做数据持久化的解决方案及底层原理是什么
    本篇内容介绍了“Redis做数据持久化的解决方案及底层原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录数据持久化RDB生成方法s...
    99+
    2023-06-20
  • C++数据结构分析多态的实现与原理及抽象类
    目录多态的概念虚函数多态构成的条件C++11override和final重载、重写和重定义(隐藏)抽象类多态的原理虚函数表原理单继承和多继承的虚表单继承的虚表多继承的虚函数表几个值得...
    99+
    2022-11-13
  • Activiti工作流学习笔记之自动生成28张数据库表的底层原理解析
    网上关于工作流引擎Activiti生成表的机制大多仅限于四种策略模式,但其底层是如何实现的,相关文章还是比较少,因此,觉得撸一撸其生成表机制的底层原理。 我接触工作流引擎Activi...
    99+
    2022-11-11
  • Java数据结构之最小堆和最大堆的原理及实现详解
    目录一、前言二、堆的数据结构三、堆的代码实现1. 实现介绍2. 入堆实现3. 出堆实现4. 小堆实现5. 大堆实现一、前言 堆的历史 堆的数据结构有很多种体现形式,包括;2-3堆、B...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作