GO基础进阶篇 (十二)、反射

什么是反射

Go语言中的反射是指在程序运行时检查程序的结构,比如变量的类型、方法的签名等。Go语言的反射包是reflect。通过反射,你可以动态地检查类型信息、获取字段和方法、调用方法等。

反射可以在运行时动态获取变量的各种信息,比如变量的类型、值等
如果是结构体,还可以获取到结构体本身的各种信息,比如结构体的字段、方法
通过反射,还可以修改变量的值、调用方法
使用反射,需要引入一个包:reflect,它定义了内个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value两部分组成,并且reflect 包提供了 reflect.Typ!alue和Type.Of和 reflect.ValueOf 两个函数来获取任意对象的 V
(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个品种的类型时在使用反射时,需要首先理解类型.就会用到种类(Kind)。

package mainimport ("fmt""reflect"
)func main() {var a float64 = 3.14fmt.Println(reflect.TypeOf(a))fmt.Println(reflect.ValueOf(a))v := reflect.ValueOf(a)if v.Kind() == reflect.Float64 {fmt.Println("v.kind() is float64")}fmt.Println(v.Type())fmt.Println(v.Float())
}

1.反射的应用场景

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

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

但是对于反射,还是有几点不太建议使用反射的理由:

  • 1、与反射相关的代码,经常是难以阅读的。在软件工程中代码可读性也是一个非常重要的指标。
  • 2、Go语言作为一门静态语言,编码过程中,编译器能提发现一些类型错误,但是对于反射代码是无能为力的。所可能会运行很久,才会出错,这时候经常是直接panic,可会造成严重的后果。
  • 3、反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级。所以,对于一个项目中处于运行效率关钱位置的代码,尽量避免使用反射特性。

2. 反射获取变量信息

package mainimport ("fmt""reflect"
)type User struct {Name stringAge  intSex  string
}func (user User) Say(msg string) {fmt.Println("user说", msg)
}
func main() {user := User{Name: "xiaolong", Age: 18, Sex: "男"}reflectGetInfo(user)
}func reflectGetInfo(input interface{}) {//获取参数类型getType := reflect.TypeOf(input)fmt.Println("type is", getType.Name())fmt.Println("kind is", getType.Kind())//获取值getValue := reflect.ValueOf(input)fmt.Println("getValue is", getValue)//通过反射获取反射结果内的字段与方法for i := 0; i < getType.NumField(); i++ {filed := getType.Field(i)value := getValue.Field(i).Interface()fmt.Println(filed.Name, filed.Type, value)}for i := 0; i < getType.NumMethod(); i++ {method := getType.Method(i)fmt.Println(method.Name, method.Type)}
}

3.反射修改对象的值

package mainimport ("fmt""reflect"
)func main() {var num float64 = 1.23point := reflect.ValueOf(&num) //想要通过指针修改值,需要传入指针newValue := point.Elem()fmt.Println(newValue.Kind())fmt.Println(newValue.Type())fmt.Println(newValue.CanSet())if newValue.CanSet() {newValue.SetFloat(3.14)}fmt.Println(num)
}

修改结构体

package mainimport ("fmt""reflect"
)type User struct {Name stringAge  intSex  string
}func (user User) Say(msg string) {fmt.Println("user说", msg)
}
func main() {user := User{Name: "xiaolong", Age: 18, Sex: "男"}fmt.Println(user)newValue := reflect.ValueOf(&user)if newValue.Kind() == reflect.Ptr { //首先是指针valueTemp := newValue.Elem()if valueTemp.CanSet() {valueTemp.FieldByName("Name").SetString("dalong")valueTemp.FieldByName("Age").SetInt(38)}}fmt.Println(user)
}

4.反射调用方法函数

方法调用

package mainimport ("fmt""reflect"
)type User struct {Name stringAge  intSex  string
}func (user User) Say(msg string) {fmt.Println("user说", msg)
}func (user User) GetInfo() {fmt.Println("user 信息", user.Name, user.Age)
}func main() {user := User{Name: "xiaolong", Age: 18, Sex: "男"}//reflectGetInfo(user)fmt.Println(user)//无参数方法调用value := reflect.ValueOf(user)value.MethodByName("GetInfo").Call(nil)//有参数方法调用args := make([]reflect.Value, 1)args[0] = reflect.ValueOf("反射调用")value.MethodByName("Say").Call(args)
}

函数调用

package mainimport ("fmt""reflect"
)func main() {v1 := reflect.ValueOf(func1)v1.Call(nil)v2 := reflect.ValueOf(func2)args := make([]reflect.Value, 2)args[0] = reflect.ValueOf(1)args[1] = reflect.ValueOf("gagaga")v2.Call(args)v3 := reflect.ValueOf(func3)args1 := make([]reflect.Value, 2)args1[0] = reflect.ValueOf(1)args1[1] = reflect.ValueOf("gagaga")res := v3.Call(args1)fmt.Println(res[0].Interface())
}func func1() {fmt.Println("无参数fun1")
}
func func2(i int, s string) {fmt.Println("有参数fun2", i, s)
}
func func3(i int, s string) string {fmt.Println("有参数fun3", i, s)return s
}

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

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

相关文章

linux系统nginx工具的一些应用

nginx高级应用 虚拟目录监控模块配置文件创建用户名密码客户端访问 限制传输速度&#xff08;服务层&#xff09; nginx配置文件中的每个语句要以 ; 结尾 虚拟目录 配置文件中的server块中编辑&#xff1a;location /test {alias /usr/share/nginx/html; //映射的是/usr…

定时器中断控制的独立式键盘扫描实验

#include<reg51.h> //包含51单片机寄存器定义的头文件 sbit S1P1^4; //将S1位定义为P1.4引脚 sbit S2P1^5; //将S2位定义为P1.5引脚 sbit S3P1^6; //将S3位定义为P1.6引脚 sbit S4P1^7; //将S4位定义为P1.7引脚 unsigned char keyval; /…

知识笔记(八十)———链式语句中join用法

join通常有下面几种类型&#xff0c;不同类型的join操作会影响返回的数据结果。 INNER JOIN: 等同于 JOIN&#xff08;默认的JOIN类型&#xff09;,如果表中有至少一个匹配&#xff0c;则返回行LEFT JOIN: 即使右表中没有匹配&#xff0c;也从左表返回所有的行RIGHT JOIN: 即使…

50天精通Golang(第18天)

web开发介绍、iris框架安装、HTTP请求和返回、Iris路由处理 一 Web项目开发介绍及实战项目介绍 1.1 引言 本系列课程我们将学些Golang语言中的Web开发框架Iris的相关知识和用法。通过本系列视频课程&#xff0c;大家能够从零到一经历一个完整项目的开发&#xff0c;并在课程…

[树莓派]给树莓派装pyinstaller环境

安装&#xff1a; sudo pip3 install pyinstaller 但是打包后会发现报错&#xff1a; Fatal error: PyInstaller does not include a pre-compiled bootloader for your platform. For more details and instructions how to build the bootloader see https://pyinstaller.…

Golang语言switch case

Golang语言使用switch语句可方便地对大量的值进行条件判断。 练习&#xff1a;判断文件类型,如果后缀名是.html输入text/html, 如果后缀名.css 输出text/css ,如果后缀名是.js 输出text/javascript Go语言规定每个switch只能有一个default分支。 extname : ".a"swit…

【栈】Leetcode 496 下一个更大元素I

【栈】Leetcode 496 下一个更大元素I 解法1 两个单调栈解法2 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法1 两个单调栈 两个栈进行操作&#xff0c;一个栈用来遍历寻找&#xff0c;一个栈用来保留 将nums2中的元素…

NLP论文阅读记录 - 2021 | WOS 利用 ParsBERT 和预训练 mT5 进行波斯语抽象文本摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.前提三.本文方法A. 序列到序列 ParsBERTB、mT5 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 Leveraging ParsBERT and Pretrained …

1.6 面试经典150题 - 买卖股票的最佳时机

买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易…

鸿蒙开发之组合手势

当我们需要支持多个手势的时候&#xff0c;可以通过GestureGroup来实现&#xff0c;如下实现了同时支持Tap和Pan手势 import Prompt from system.prompt Entry Component struct OfficialGestureGroupPage {State message: string Hello Worldbuild() {Column() {Column() {T…

STM32WL用户手册学习

介绍 STM32Cube是意法半导体的原创产品&#xff0c;通过减少开发工作量、时间和成本来显著提高开发人员的生产力。STM32Cube涵盖了整个STM32产品组合。 STM32Cube包括&#xff1a; 一套用户友好的软件开发工具&#xff0c;涵盖项目开发从设计到生产&#xff0c;其中&#xf…

算法第十九天-二叉搜索树节点最小距离

二叉搜索树节点最小距离 题目要求 解题思路 今天题目重点&#xff1a; 1.二叉搜索树&#xff08;BST&#xff09; 2.任意两个不同节点 遇到二叉搜索树&#xff0c;立即想到这句话&#xff1a;[二叉搜索树&#xff08;BST&#xff09;的中序遍历是有序的]。这是解决所有二叉搜…

1.1 面试经典 150 题-合并两个有序数组

合并两个有序数组 方法一&#xff1a;先合并再排序 class Solution:def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:"""Do not return anything, modify nums1 in-place instead."""# 先合并for i in range…

全网最细RocketMQ源码四:消息存储

看完上一章之后&#xff0c;有没有很好奇&#xff0c;生产者发送完消息之后&#xff0c;server是如何存储&#xff0c;这一章节就来学习 入口 SendMessageProcessor.processRequest private CompletableFuture<RemotingCommand> asyncSendMessage(ChannelHandlerCont…

【现代密码学】笔记5--伪随机置换(分组加密)《introduction to modern cryphtography》

【现代密码学】笔记5--伪随机置换&#xff08;分组加密&#xff09;《introduction to modern cryphtography》 写在最前面5 伪随机排列实践构造&#xff08;块密码/分组密码&#xff09; 写在最前面 主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充&…

pve虚拟机的改名和修改ID

PVE的虚拟机名字在web界面是无法修改id和名字的。要注意id和名字不能重。 在使用备份时就发现虚拟机是以虚拟机id作为维一标识&#xff0c;如果有多台pve节点&#xff0c;但共用同一个nfs目录备份或使用同一个pbs进行备份时就必须保障id的唯一性。这时可以使用这个方法来进行补…

MySQL使用通配符进行数据搜索以及过滤

目录 1.什么是通配符&#xff1f; 2.通配符之→百分号(%) 3.通配符之→下划线(_) 4.通配符使用注意事项 *本文涉及概念来源于图灵程序设计丛书&#xff0c;数据库系列——《MySQL必知必会》 1.什么是通配符&#xff1f; 通配符(wildcard) &#xff1a;用来匹配值的一部分…

返利机器人详细解读,纯属个人观点

返利机器人详细解读&#xff0c;纯属个人观点 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我将为你详细解读返利机器人的发展历程、争议焦点以及…

scrollTop与offsetTop解决小分辨率区域块向上滚动效果效果,结合animation与@keyframes实现标题左右闪动更换颜色效果。

scrollTop 是一个属性&#xff0c;它表示元素的滚动内容垂直滚动条的位置。对于可滚动元素&#xff0c;scrollTop 属性返回垂直滚动条滚动的像素数&#xff0c;即元素顶部被隐藏的像素数。 offsetTop 是一个属性&#xff0c;用于获取一个元素相对于其父元素的垂直偏移量&…

【Mybatis-Plus】mybatisplus更新时,实体字段为空,数据库不更新的解决方案

一、背景描述 项目技术栈&#xff1a;jdk (1.8) spring boot (2.1.0) mybatis-plus (3.5.1) 数据库&#xff1a; MySQL 字段类型&#xff1a;varchar 和 Integer 从前端传过来的数据实体字段&#xff0c; convertType 和 step 设为null时&#xff0c;使用mybatis-plus 的…