go reflect 反射

目录

一、反射

1、reflect.Type 和 reflect.Value

2、rtype 和 rvalue

3、reflect.TypeOf 工作原理

4、reflect.ValueOf 工作原理

5、reflect.ValueOf 与 reflect.TypeOf 比较

6、性能优化建议

二、问题:

1、静态类型和动态类型

2、值类型与引用类型

(1)值类型(Value Types)

(2)非值类型(Reference Types)

3、对于需要反射的结构体,使用引用类型结构体是不是更好


一、反射

1、reflect.Typereflect.Value

Go语言的反射(reflection)是通过reflect包来实现的,它提供了一些工具用于在运行时检查类型和值。reflect 的核心功能依赖于 reflect.Typereflect.Value 两个结构。reflect.Typereflect.Value 都是封装了底层数据结构,用来访问动态类型和动态值。

  • reflect.Type:表示类型信息,用来获取静态类型的信息(如类型名、类型的大小、类型的字段等)。
  • reflect.Value:它是一个结构体,封装了一个指向实际数据的指针。通过它可以获取对象的值、修改值或调用方法

2、rtypervalue

每个 Go 类型都有一个称为 rtype 的结构体,它是类型信息的底层实现。rvalue 是指实际数据值的底层实现。Go 的运行时会通过反射把数据和类型信息组合在一起,从而允许我们在运行时动态地访问或修改数据。

(1)rtype:由 Go 编译器在编译时生成,包含类型的元数据。对于每个类型(包括结构体、数组、切片、基本类型等)都有一个对应的 rtype,它在程序运行时通过反射机制被加载到内存中,以供反射操作使用。

  • 对于静态类型(如 int、struct、slice等),Go 运行时在程序启动时就加载了类型信息。reflect.TypeOf 只是返回这些类型元数据的引用,因此在这些情况下,reflect.TypeOf 的开销相对较小。对于结构体类型,编译器会根据结构体定义生成一个 rtype,这个 rtype 包含了结构体的字段信息、字段顺序、字段类型、大小等信息。
  • 对于动态类型(接口类型interface),reflect.TypeOf 需要根据实际值的动态类型来查找类型信息,涉及到更多的运行时查找操作。

(2)rvalue:在运行时创建,当通过 reflect.ValueOf() 等反射操作获取一个值时,Go 会创建一个 rvalue。它封装了数据的实际值,并与 rtype 一起用于实现反射的功能。

  • 对于值类型(如 int、array、struct 等),rvalue 会直接封装该值。
  • 对于引用类型或指针rvalue 会封装指向实际内存中数据的指针。

3、reflect.TypeOf 工作原理

当调用 reflect.TypeOf 时,Go 会查询该类型的 rtype。每个 Go 类型都有一个称为 rtype 的结构体,rtype 会包含关于该类型的元数据信息,包括类型的大小、字段、方法等。

  • 查询类型元数据reflect.TypeOf 会访问传入对象的类型信息,通常这个信息是通过指向 rtype 结构体的指针来存储的。
  • 返回类型信息reflect.TypeOf 会根据传入的值返回一个 reflect.Type,这个 reflect.Type 本质上是对 rtype 的封装,包含了该类型的各种元数据信息。

4、reflect.ValueOf 工作原理

当调用 reflect.ValueOf 时,Go 会返回一个 reflect.Value 对象,该对象封装了传入对象的实际数据(指向底层数据的指针)以及该数据的动态类型。通过 reflect.Value,可以读取或修改对象的值。

  • 类型信息reflect.ValueOf 会通过 reflect.TypeOf 获取传入对象的类型信息,即 rtype,并将其存储在 reflect.Value 中。
  • 内存分配:对于非值类型的对象(如指针、切片、数组、interface、chan等),reflect.ValueOf 会创建一个新的 reflect.Value 实例,封装传入值的内存地址(指针)或直接复制值。
  • 复制操作:对于值类型的对象(如 int、array、struct等),reflect.ValueOf 可能会创建该值的副本。这意味着如果传入的是大对象或结构体,可能会涉及到较大的内存分配和复制操作。

5、reflect.ValueOf 与 reflect.TypeOf 比较

  • reflect.TypeOf:只返回类型信息,获取的是 reflect.Type。它仅仅是对静态类型信息的封装,因此开销相对较低,特别是当类型信息已经在程序启动时加载到内存中的时候。reflect.TypeOf 不会涉及值的拷贝或修改。

  • reflect.ValueOf:返回的是实际的值,它不仅封装了类型信息,还封装了该值的实际数据。对于值类型,可能会发生复制;对于引用类型,通常会封装指针。此外,它还要处理值的可变性、指针封装等因素,因此它的开销通常大于 reflect.TypeOf

6、性能优化建议

  • 减少不必要的反射调用:频繁调用 reflect.ValueOf 或者其他反射函数会带来额外的性能开销。尽量避免在性能关键路径中使用反射。
  • 避免对大对象进行深拷贝:对结构体或数组等较大对象进行深拷贝可能会导致性能瓶颈。如果反射需要频繁复制数据,考虑是否可以优化数据结构或减少不必要的复制。
  • 使用引用(指针)类型,避免反射时的内存复制。

二、问题:

1、静态类型和动态类型

  • 静态类型 是编译时确定的,它决定了变量所能持有的值的种类和支持的操作。
  • 动态类型 是运行时确定的,通常与接口类型相关,反映了变量当前存储的数据的类型。
  • 静态类型不能改变,一旦确定就不可改变;动态类型是可变的,尤其是在接口类型中。
  • 静态类型由编译器进行静态类型检查;动态类型在运行时通过反射或类型断言访问。
  • 通过反射或类型断言,可以在运行时获取动态类型的信息。

2、值类型与引用类型

(1)值类型(Value Types)

值类型是指存储数据本身的类型,变量直接包含其数据的副本。当我们将一个值类型变量赋值给另一个变量时,实际上是将数据的副本拷贝了一份。改变新变量的值不会影响原始变量。

常见的值类型

  • 基本类型:如 intfloatboolstring
  • 结构体类型struct
  • 数组类型array

值类型的特点

  • 直接存储数据:值类型的变量直接包含数据本身,而不是数据的引用。
  • 复制传递:当将一个值类型变量赋值给另一个变量时,数据会被复制。这意味着两个变量在内存中互不影响,它们各自拥有自己的数据副本。
  • 内存分配:值类型通常会在栈上分配内存,数据存储在变量的内存区域。
(2)非值类型(Reference Types)

非值类型是指存储数据的引用或地址的类型,变量保存的是数据的指针(引用),而不是数据本身。当我们将一个非值类型变量赋值给另一个变量时,实际上是将数据的引用(地址)传递给新变量。此时两个变量指向相同的内存位置,修改一个变量的值会影响到另一个变量。

常见的非值类型

  • 指针类型pointer
  • 切片类型slice
  • 映射类型map
  • 通道类型chan
  • 接口类型interface

非值类型的特点

  • 存储数据的引用:非值类型的变量存储的是数据的引用(指针),而不是数据本身。
  • 共享数据:当将一个非值类型变量赋值给另一个变量时,它们共享同一块内存区域。修改其中一个变量会影响到其他所有引用同一内存位置的变量。
  • 内存分配:非值类型通常会在堆上分配内存(但也有可能在栈上分配,具体取决于编译器的优化)。

3、对于需要反射的结构体,使用引用类型结构体是不是更好

        在 Go 中,对于需要反射的结构体,使用引用类型结构体(即结构体指针)通常比使用值类型结构体更优。

        减少内存开销。当传递一个结构体变量时,会发生值的复制。如果传递的是结构体指针,那么反射操作将直接作用于原始结构体,而不是副本,这避免了不必要的内存开销。

        提高灵活性。结构体指针可以直接修改原始结构体的字段,而值类型结构体的修改不会影响到原始数据。

        避免不必要的 Elem 调用。如果使用结构体的值类型(即传递结构体副本),在反射时需要使用 Elem() 来解引用结构体指针。如果使用结构体指针,则不需要。

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

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

相关文章

【深度学习】LSTM、BiLSTM详解

文章目录 1. LSTM简介:2. LSTM结构图:3. 单层LSTM详解4. 双层LSTM详解5. BiLSTM6. Pytorch实现LSTM示例7. nn.LSTM参数详解 1. LSTM简介: LSTM是一种循环神经网络,它可以处理和预测时间序列中间隔和延迟相对较长的重要事件。LSTM通…

使用ookii-dialogs-wpf在WPF选择文件夹时能输入路径

在进行WPF开发时,System.Windows.Forms.FolderBrowserDialog的选择文件夹功能不支持输入路径: 希望能够获得下图所示的选择文件夹功能: 于是,通过NuGet中安装Ookii.Dialogs.Wpf包,并创建一个简单的工具类: …

【leetcode练习·二叉树】用「分解问题」思维解题 II

本文参考labuladong算法笔记[【强化练习】用「分解问题」思维解题 II | labuladong 的算法笔记] 技巧一 类似于判断镜像二叉树、翻转二叉树的问题,一般也可以用分解问题的思路,无非就是把整棵树的问题(原问题)分解成子树之间的问…

Qt 编写插件plugin,支持接口定义信号

https://blog.csdn.net/u014213012/article/details/122434193?spm1001.2014.3001.5506 本教程基于该链接的内容进行升级,在编写插件的基础上,支持接口类定义信号。 环境:Qt5.12.12 MSVC2017 一、创建项目 新建一个子项目便于程序管理【…

PaaS云原生:分布式集群中如何构建自动化压测工具

场景 测试环境中,压测常常依赖环境中的各种工具获取基础信息,而这些工具可能集中在某个中控机上,此时想打造的自动化工具的运行模式是: 通过中控机工具获取压测所需的基本信息在中控机部署压测工具,实际压测任务分发…

关于sass在Vue3中编写bem框架报错以及警告问题记录

在编写完bem框架后 在vite.config.ts文件进行预编译处理时,报错的错误 1. 处理方式:使用新版api, 如图: 2. 处理方式:使用 use 替换掉 import, 如图: 3. 处理方式:使用路径别名&am…

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片: 二、 产品特性: 4G性能:支持2K超高清图传,数据传输不掉帧,更稳定。 独立北…

【前端】深入浅出的React.js详解

React 是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发并维护。随着 React 的不断演进,官方文档也在不断更新和完善。本文将详细解读最新的 React 官方文档,涵盖核心概念、新特性、最佳实践等内容,帮助开发者更好地理解…

【Elasticsearch入门到落地】1、初识Elasticsearch

一、什么是Elasticsearch Elasticsearch(简称ES)是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。它使用Java编写,基于Apache Lucene来构建索引和提供搜索功能,是一个分布式、可扩展、近实…

扫雷游戏代码分享(c基础)

hi , I am 36. 代码来之不易👍👍👍 创建两个.c 一个.h 1:test.c #include"game.h"void game() {//创建数组char mine[ROWS][COLS] { 0 };char show[ROWS][COLS] { 0 };char temp[ROWS][COLS] { 0 };//初始化数…

ORA-01092 ORA-14695 ORA-38301

文章目录 前言一、MAX_STRING_SIZE--12C 新特性扩展数据类型 varchar2(32767)二、恢复操作1.尝试恢复MAX_STRING_SIZE参数为默认值2.在upgrade模式下执行utl32k.sql 前言 今天客户发来一个内部测试库数据库启动截图报错,描述是“上午出现服务卡顿,然后重…

ODOO学习笔记(3):Odoo和Django的区别是什么?

Odoo和Django都是基于Python的开源框架,但它们的设计目标和用途有所不同: 设计目标和用途: Odoo:Odoo是一个企业资源规划(ERP)系统,它提供了一套完整的商业管理软件,包括会计、库存…

零基础玩转IPC之——海思平台实现P2P远程传输实验(基于TUTK,国科君正全志海思通用)

老规矩,先做实验测试。以本店Hi3516EV200\GK7205开发板为例,其他开发板操作类似。 将源码包p2p-h264.tgz放到虚拟机,解压,编译 tar -jxvf p2p-h264.tgz cd p2p-h264 make clean make 得到可执行文件p2p-h264 启动开发板&…

如何理解DDoS安全防护在企业安全防护中的作用

DDoS安全防护在安全防护中扮演着非常重要的角色。DDoS(分布式拒绝服务)攻击是一种常见的网络攻击,旨在通过向目标服务器发送大量请求,以消耗服务器资源并使其无法正常运行。理解DDoS安全防护的作用,可以从以下几个方面…

Python如何从HTML提取img标签下的src属性

目录 前提准备步骤1. 解析HTML内容2. 查找所有的img标签3. 提取src属性 完整代码 前提准备 在处理网页数据时,我们经常需要从HTML中提取特定的信息,比如图片的URL。 这通常通过获取img标签的src属性来实现。 在开始之前,你需要确保已经安装…

Redis主从复制(replication)

文章目录 是什么作用使用案例实操主从复制原理和工作流程slave启动,同步初请首次连接,全量复制心跳持续,保持通信进入平稳,增量复制从机下线,重连续传 复制的缺点 是什么 主从复制,master以写为主&#xf…

Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别

目录 一、概念 1、纹理过滤 2、邻近过滤 3、线性过滤 二、邻近过滤和线性过滤的区别 三、源码下载 一、概念 1、纹理过滤 当纹理被应用到三维物体上时,随着物体表面的形状和相机视角的变化,会导致纹理在渲染过程中出现一些问题,如锯齿…

记录日志中logback和log4j2不能共存的问题

本文章记录设置两个日志时候,控制台直接报错 标黄处就是错误原因:1. SLF4J(W):类路径包含多个SLF4J提供程序。 SLF4J(W):找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W):找到提供程序[ch.qos.log .classi…

【PGCCC】Postgresql Toast 原理

前言 上篇博客讲述了 postgresql 如何存储变长数据,它的应用主要是在 toast 。Toast 在存储大型数据时,会将它存储在单独的表中(称为 toast 表)。因为 postgresql 的 tuple(行数据)是存在在 Page 中的&…

C指针创建三维数组

定义的时候变量的位置就是最后一个星号的位置 int*** matrix3d_int(int nz, int nrh, int nch) {int*** matrix (int***)malloc(nz * sizeof(int**));for (int z 0; z < nz; z) {matrix[z] (int**)malloc(nrh * sizeof(int*));for (int y 0; y < nrh; y) {matrix[z][…