Golang反射相关知识总结

1. Golang反射概述

Go语言的反射(reflection)是指在运行时动态地获取类型信息和操作对象的能力。在Go语言中,每个值都是一个接口类型,这个接口类型包含了这个值的类型信息和值的数据,因此,通过反射,可以获取一个值的类型信息,调用该值的方法,或者修改该值的属性等。
Go语言中的反射机制主要通过reflect包来实现。reflect包提供了Type、Value和Kind三个类型,分别表示类型信息、值信息和值的种类。其中,Type类型可以表示任何类型的信息,包括基本类型、结构体、接口类型、函数类型等。Value类型可以表示任何值,包括基本类型、结构体、接口类型、函数类型等。Kind类型则表示值的种类,如int、float、string等。
通过reflect包,可以获取一个类型的信息,例如:

package mainimport ("fmt""reflect"
)type MyStruct struct {Name stringAge  int
}func main() {t := reflect.TypeOf(MyStruct{})fmt.Println("Type:", t.Name())fmt.Println("Kind:", t.Kind())for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Printf("%s (%s)\n", field.Name, field.Type.Name())}
}

实现结果:
在这里插入图片描述
上述代码中,使用reflect.TypeOf函数获取MyStruct类型的信息,然后打印出类型名称、类型种类和字段信息。
同时,也可以通过reflect包获取一个值的信息,例如:

package mainimport ("fmt""reflect"
)type MyStruct struct {Name stringAge  int
}func main() {v := MyStruct{Name: "Tom", Age: 18}rv := reflect.ValueOf(v)fmt.Println("Type:", rv.Type().Name())fmt.Println("Kind:", rv.Kind())for i := 0; i < rv.NumField(); i++ {field := rv.Field(i)fmt.Printf("%s: %v\n", field.Type().Name(), field.Interface())}
}

实现结果:
在这里插入图片描述
上述代码中,使用reflect.ValueOf函数获取MyStruct类型的值信息,并通过rv.Type()函数获取值的类型信息,通过rv.Kind()函数获取值的种类信息,并打印出字段名称和值。同时,还可以通过rv.FieldByName函数获取指定名称的字段信息,并通过rv.FieldByNameFunc函数获取符合条件的字段信息。
除了获取类型和值的信息之外,反射还可以动态地创建类型、创建值、调用方法和修改属性等。例如,可以使用reflect.New函数动态创建一个新的值,可以使用reflect.ValueOf函数设置一个值的属性,可以使用reflect.MethodByName函数调用一个方法,可以使用reflect.ValueOf函数修改一个值的属性等。

2. 简单的反射实现修改变量的值

下面示例中,简单演示了如何直接修改City变量的值:

package mainimport ("fmt""reflect"
)type Address struct {City  stringState string
}
type Person struct {Name    stringAge     intAddress Address
}func main() {p := Person{Name: "Alice",Age:  25,Address: Address{City:  "New York",State: "NY",},}// 通过反射获取到嵌套结构体中需要修改的字段的反射值field := reflect.ValueOf(&p).Elem().FieldByName("Address").FieldByName("City")// 判断该字段是否可修改,如果不可修改,则需要使用 `Elem()` 函数获取到该字段的可修改的反射值if !field.CanSet() {field = field.Elem()}// 根据需要修改的值的类型,使用反射包中的 `SetValue()` 函数来修改该字段的值field.SetString("Los Angeles")// 输出: {Alice 30 {Los Angeles NY}}fmt.Println("the result is:", p)
}

输出结果:
在这里插入图片描述
然而,在实际运用中,第一种方式往往不够灵活,对于使用者而言,更多的想直接调用某个方法,通过传入需要修改的变量的路径以及修改后的值来直接实现,基于此,对第一种方式进行改进。

3. 实现传入路径修改变量的值

通过将具体操作封装为ModifyValue函数来实现,传入路径后,对路径进行拆解

package mainimport ("fmt""reflect""strings"
)type Address struct {City  stringState string
}
type Person struct {Name    stringAge     intAddress Address
}func ModifyValue(req *Person, modifyPath string, value interface{}) bool {// 通过反射获取 req 的值reqValue := reflect.ValueOf(req).Elem()// 根据 path 找到 req 中需要修改的字段substrings := strings.Split(modifyPath, ".")for i, substring := range substrings {if i == 0 {continue}reqValue = reqValue.FieldByName(substring)if !reqValue.IsValid() {return false}}// 将 value 转换成需要修改的字段的类型newValue := reflect.ValueOf(value).Convert(reqValue.Type())// 设置修改后的值reqValue.Set(newValue)return true
}func main() {req := Person{Name: "Tom",Age:  12,Address: Address{City:  "New York",State: "NY",},}result := ModifyValue(&req, "req.Address.City", "Los Angeles")fmt.Printf("the result is:%v, req.Address.City:%v", result, req.Address.City)
}

实现结果:
在这里插入图片描述
总之,Go语言的反射机制为程序提供了一种动态地获取类型信息和操作对象的能力,但是反射的效率较低,也要谨慎使用。

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

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

相关文章

JAVA高级技术入门(单元测试,反射,注解,动态代理)

JAVA高级技术入门&#xff08;单元测试&#xff0c;反射&#xff0c;注解&#xff0c;动态代理&#xff09; 一、Junit单元测试二、反射1.认识反射&#xff0c;获取类概念&#xff1a;快速入门&#xff1a;获取Class对象的三种方式 2.1获取类的构造器2.2获取类的构造器的作用&a…

【算法专题突破】滑动窗口 - 找到字符串中所有字母异位词(14)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;438. 找到字符串中所有字母异位词 - 力扣&#xff08;Leetcode&#xff09; 这道题很好理解&#xff0c;就是找出从不同位置开始的所有异位词。 2. 算法原理 那我们该如…

Android笔记(二十九):利用python自动生成多语言

背景 项目需要支持十几种多语言&#xff0c;而且每个版本的新功能ui都有很多地方需要多语言&#xff0c;如果手动添加非常耗时&#xff0c;于是设计了一个python脚本&#xff0c;通过excel表格转化多语言到项目values/strings文件内 步骤 android工程项目结构 脚本位于langu…

MAUI android连接sqlserver

PDA是android系统&#xff0c;调用金蝶云星空webapi实现仓库收发料&#xff0c;使用读取webapi有些功能无法实现&#xff0c;需要直接读写数据库&#xff0c;读取报错&#xff0c;如图&#xff1a; 用控制台程序测试正常读取 google搜索了一圈&#xff0c; 都需要使用ssl证书才…

pdf添加水印

给pdf文件添加水印 引入依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency>添加水印 package com.it2.pdfdemo02.util;import com.itextpdf.tex…

MySql安装包配置

电脑重配过多次&#xff0c;此为mysql安装记录贴&#xff0c;方便查阅 从官网下载的安装包进行本地配置 下载地址 解压下载下来的zip压缩包 解压出来的文件中新增配置my.ini文件 [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录 basedirD:\\software\\package\\M…

知识图谱实战导论:从什么是KG到LLM与KG/DB的结合实战

前言 本文侧重讲解&#xff1a; 什么是知识图谱LLM与langchain/数据库/知识图谱的结合应用 比如&#xff0c;虽说基于知识图谱的问答 早在2019年之前就有很多研究了&#xff0c;但谁会想到今年KBQA因为LLM如此突飞猛进呢 第一部分 知识图谱入门导论 //待更.. 第二部分 LLM与…

ipad手写笔有必要买吗?好用的平板触控笔

众所周知&#xff0c;随着Apple pencil的出现&#xff0c;市面上出现越来越多平替电容笔的出现&#xff0c;无论是价格和功能&#xff0c;几乎都很接近。很多小伙伴不知如何下手&#xff0c;不知道如何从众多品牌中挑选出适合自己的电容笔&#xff0c;今天我为大家总结一下网上…

LeetCode 428. Serialize and Deserialize N-ary Tree【树,BFS,DFS】困难

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

9月15日作业

Qt代码 #include "mywnd.h"//构造函数的定义 mywnd::mywnd(QWidget *parent): QWidget(parent) //显性调用父类的有参构造完成对子类从父类继承下来成员的初始化工作 {//窗口设置this->resize(QSize(500, 433));this->setWindowTitle("Widget&quo…

Vue前端页面打印

前端依赖10-插件"print-js": “^1.6.0” 一&#xff1a;简介 print-js 是一个 Vue.js 插件&#xff0c;用于在 Vue.js 项目中实现打印功能。它依赖于 print-js 库&#xff0c;所以需要安装这个库。 能实现以下功能&#xff1a; PDF打印&#xff08;默认&#xff…

【Linux】线程的概念

文章目录 &#x1f4d6; 前言1. 线程的引入1.1 执行流&#xff1a;1.2 线程的创建&#xff1a;1.3 线程的等待&#xff1a; 2. 查看线程2.1 链接线程库&#xff1a;2.2 ps -aL&#xff1a; 3. 页表的认识3.1 二级页表&#xff1a;3.2 页表的实际大小&#xff1a; 4. 再看线程4.…