Go-知识反射

Go-知识反射

  • 1. 接口
    • 1.1 类型
    • 1.2 interface 类型
      • 1.2.1 interface 变量
      • 1.2.2 实现接口
      • 1.2.3 复合类型
      • 1.2.4 空 interface
  • 2. 反射定律
    • 2.1 reflect 包
    • 2.2 反射可以将 interface 类型变量转换为反射对象
    • 2.3 反射可以将反射对象还原成 interface 对象
    • 2.4 反射对象可修改,value 值必须是可设置的
  • 3. 思考 接口实现和接口继承

gitio: https://a18792721831.github.io/

1. 接口

1.1 类型

Go 语言是静态类型语言,比如 int, float32,[]byte 等等

https://blog.csdn.net/a18792721831/article/details/135572152

每个变量都有一个静态类型,在编译时就确定了。

type Myint int
var i int
var j Myint

在上面的代码中, i 和 j 是不同的静态类型,尽管二者的底层类型都是 int, 但是在没有类型转换的情况下是不可以相互赋值的
除了基础类型,还有一些由基础类型组成的复合类型,比如数组,结构体,之神,切片,map和channel 等
同时 interface 也是一种复合类型。

1.2 interface 类型

interface 类型代表一个特定的方法集,方法集中的方法称为接口。

type Person interface {Speak()
}

Person就是一个接口类型,包含一个 Speak() 方法。

1.2.1 interface 变量

interface 是一种复合类型,既然是类型,就能声明变量

var p Person

声明的变量 p 没有赋值,其值为 nil

p 能存储什么值 ?

1.2.2 实现接口

在Java或者c/c++中,实现接口需要使用特定的关键字,声明实现的接口。
在Go里面有一个鸭子类型的思想:
“鸭子类型”(Duck Typing)是一种编程概念,它的名字来源于英语中的一句谚语:
“如果它走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子”。
在编程中,鸭子类型的思想是:
一个对象的类型不是由它从哪个类继承或者它实现了哪些接口来决定的,
而是由它有哪些行为(即方法)来决定的。
在 Go 语言中,鸭子类型的概念主要通过接口(interface)来实现的。
在 Go 中,接口是一种类型,它定义了一组方法,但是没有实现这些方法。
任何实现了接口中所有方法的类型都被认为实现了该接口,无论这个类型的定义在哪里,
都不需要显式地声明这个类型实现了这个接口。
比如

type Man struct{Name string
}
func (m Man)Speak() {fmt.Println("hello , I'am " + m.Name)
}

此时结构体 Man 就实现了 Speak 方法
那么 结构体 Man 的变量就可以存储到 Person 变量中

var p Person
var m Man
p = m

interface 变量可以存储任意实现了该接口类型的变量

1.2.3 复合类型

interface 类型的变量在存储某个变量时,会同时保存变量类型和变量值:
在这里插入图片描述

tab 保存变量类型以及方法集
data 保存变量的指针
interface 变量同时保存变量值和变量类型。

1.2.4 空 interface

空 interface 是一种非常特殊的 interface 类型,没有指定任何方法集,因此,
任意类型都可以认为实现了 空 interface ,那么 空 interface 也就可以存储任意值

有点像 Java 里面 的 Object 类

2. 反射定律

interface 类型有一个 (value,type) 对,反射就是操作 interface 的 (value, type )的机制。
换句话来说,就是Go 提供方法来获取 interface 的 value 和 type.

2.1 reflect 包

反射包,reflect 包提供了reflect.Typereflect.Value两种类型,用于表示 interface 中的 value 和 type.
同时 reflect 包提供了两个方法用于获取 interface 的 value 和 type

func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value

在这里插入图片描述

reflect.Type 和 reflect.Value 称为反射对象

2.2 反射可以将 interface 类型变量转换为反射对象

func TestRef(t *testing.T) {var x float64 = 3.14tf := reflect.TypeOf(x)fmt.Println("type:", tf)vf := reflect.ValueOf(x)fmt.Println("value:", vf)
}

在这里插入图片描述

reflect.TypeOfreflect.ValueOf中,两个函数的入参是 interface 类型
在调用的时候,发生了隐式的类型转换
将 float64 转为了 interface{} 类型
这样就实现了 interface 变量转为 反射对象
这也是反射的开端,拿到了反射对象就可以进行其他的操作了

2.3 反射可以将反射对象还原成 interface 对象

反射对象 与 interface 对象是可以相互转化的。

func TestUnRef(t *testing.T) {var A interface{}A = 100vo := reflect.ValueOf(A)B := vo.Interface()if A == B {fmt.Println("same")}
}

在这里插入图片描述

通过 reflect.ValueOf 获取接口变量 A 的反射对象,然后又通过反射对象的 Interface 获取 B ,最终 A 和 B 是相同的。

2.4 反射对象可修改,value 值必须是可设置的

通过反射可以将 interface 类型的变量转换为反射对象,可以使用该反射对象设置 interface 变量持有的值。

func TestChgRef(t *testing.T) {var x float64 = 3.14vf := reflect.ValueOf(&x)vf.Elem().SetFloat(4.14)fmt.Println(x)fmt.Println(vf.Elem().Interface())
}

在这里插入图片描述

通过reflect.ValueOf获取 interface 对象的反射对象,然后通过Elem获取指向 interface 对象的指针
接着就可以通过指针赋值了
在打印的时候,直接打印 interface 对象,发现值已经被修改
打印反射对象通过Interface() 获取的 interface 对象,也就是原对象,值也是修改的。

需要注意函数调用的 传参,引用传递还是值传递

如果是值传递,就是不可修改的,就不能 set

func TestChgRefPanic(t *testing.T) {var x float64 = 3.14vf := reflect.ValueOf(x)vf.SetFloat(4.14)fmt.Println(x)fmt.Println(vf.Interface())
}

在这里插入图片描述

因为是值传递,所以在函数内部相当于是复制了一个副本,修改副本的值,并不会同步到原值,相当于是无效的修改,因此就panic了

3. 思考 接口实现和接口继承

如果有如下代码:

type Person interface {Speak()
}
type Man struct {Name string
}
func (m Man)Speak() {fmt.Println(m.Name)
}
type Woman struct{PersonName string
}
func (w Woman)Speak() {fmt.Println(w.Name)
}

那么不管是 Woman 还是 Man 都能调用 Speak 方法,那么有什么区别呢?
从接口实现的角度理解,不管是 Woman 还是 Man 都实现是了 Person 接口。
那么在反射中来说,Person 变量都可以存储 Woman 或者 Man 的变量。
从接口继承的角度理解
Man 只是实现了接口,而 Woman 组合了 Person,这意味着 Woman 可以隐式的拥有一个 Person 类型的变量
在调用的时候,可以调用 Person.Speak 。
简单来说,可以这么理解:
Man 实现 Person
Woman 实现 Person 并且 组合 Person
在方法调用上,Man 只能调用自己实现的 Speak 逻辑
Woman 不仅可以调用自己的逻辑,还可以调用 其他实现的 Speak 逻辑

可以借用 Java 里面 Woman 继承了 A 类,并且实现了 Person 接口,A类实现了 Person 接口,
在方法调用上,可以让 Woman 调用A.Speak

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

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

相关文章

Oracle权限安全管理

实验内容 本次实验先使用system用户连接 温馨提示:题目要求切换账户登录的时候自己记得切换,本文章只提供相应的SQL语句 在表空间BOOKTBS1(实验4第1题已创建)创建一张表BOOKS,其字段如下:: SQL> create…

一次性语音芯片:重塑语音识别技术,引领智能化生活新时代

随着一次性语音芯片的突破性进展,语音识别技术正融入我们生活的方方面面,引领着智能化生活迈向一个全新的时代。这些芯片不仅体积小巧、成本低廉,更在性能上实现了质的飞跃,能够更精确地捕捉并理解人类语音。本文将解读关于一次性…

嵌入式开发选硬件还是软件?

做了单片机软件开发很多年,和很多硬件工程师打过配合,其中大部分硬件工程师,越往后,学软件的意愿越强烈。 所以我建议是,先做软件,是比较好的发育路线。 软件开发的优势主要体现在几个方面。 第一是薪资待遇…

python爬虫实战案例——从移动端接口抓取微博评论,采用cookie登陆,数据存入excel表格,超详细(15)

文章目录 1、任务目标2、网页分析3、代码编写3.1 代码分析3.2 完整代码1、任务目标 1、目标网站:微博文章(https://m.weibo.cn/detail/4813628149072458),这是微博某一篇博文,用于本文测试 2、要求:爬取该博文下,所有一级评论和二级评论,以及每条评论的作者,最后保存至E…

Python魔法函数__iter__的用法

下面是找到的一个比较好的科学解释: Python中可迭代对象(Iterable)并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问。 1.__iter__方法的作用是让对象可以用for…

Vscode替换\n为换行符

文件内容是字符串,每行用\n分割,阅读困难,可以在vscode,用替换\n进行换行。

120多套各种类别微信小程序模板源码

微信小程序是一种轻量级的应用开发平台,由腾讯公司推出,主要应用于移动端,为用户提供便捷的服务体验。本资源包含120套微信小程序的源码,对于开发者来说是一份宝贵的参考资料,可以用来学习、研究或者作为开发新项目的起…

【Linux系统编程】环境基础开发工具使用

目录 1、Linux软件包管理器yum 1.1 什么是软件包 1.2 安装软件 1.3 查看软件包 1.4 卸载软件 2、Linux编辑器-vim 2.1 vim的概念 2.2 vim的基本操作 2.3 vim的配置 3、Linux编译器-gcc/g 3.1 gcc编译的过程​编辑​编辑​编辑 3.2 详解链接 动态链接 静态链接 4…

C++【内存管理】(超详细讲解C++内存管理以及new与delete的使用和原理)

文章目录 1.C/C内存分布2.C语言中动态内存管理方式3.C内存管理方式3.1 new/delete操作内置类型3. 2new/delete操作自定义类型 4. operator new与operator delete函数(重点)5. new和delete的实现原理5.1 内置类型5.2 自定义类型5.2.1 自定义类型调用new[]…

JAVA就业笔记6——第二阶段(3)

课程须知 A类知识:工作和面试常用,代码必须要手敲,需要掌握。 B类知识:面试会问道,工作不常用,代码不需要手敲,理解能正确表达即可。 C类知识:工作和面试不常用,代码不…

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行 引言 在现代应用开发中,随着业务需求的增长,数据库表结构和数据往往需要进行迁移和更新。迁移(Migration)是指对数据库表的结构、数据类型、索引、约束等进行修改或更新…

电脑桌面便签怎么添加,好用便签软件怎么样?

在数字化时代,电脑桌面便签是现代工作和学习中不可或缺的工具,它能够帮助用户记录重要信息、设置提醒事项并高效管理任务。那么,电脑桌面便签怎么添加,好用便签软件怎么样呢?接下来让我们一起来探讨下吧。 一&#xf…

13.3寸工业三防平板数字化工厂产线数采手持终端

在数字化工厂的建设浪潮中,高效可靠的数据采集终端至关重要。尤其在水处理、食品加工等特殊工业环境下,设备的耐用性和数据安全性面临严峻挑战。传统的平板电脑难以应对复杂的工业现场,而一款性能卓越、坚固耐用的工业三防平板则成为提升生产…

使用docker搭建lnmp运行WordPress

一,部署目的 使用 Docker 技术在单机上部署 LNMP 服务(Linux Nginx MySQL PHP)。部署并运行 WordPress 网站平台。掌握 Docker 容器间的互联及数据卷共享。 二,部署环境 操作系统:CentOS 7Docker 版本&#xff1…

路由通信 的 VLAN技术

一、VLAN基础 虚拟局域网(Virtual Local Area Network,VLAN) 根据管理功能、组织机构或应用类型对交换局域网进行分段而形成的逻辑网络。 交换机最多支持4094个VLAN,其中默认管理VLAN是VLAN1,不能创建,也…

spark:数据的关联与合并、缓存和checkpoint

文章目录 1. 数据的关联与合并1.1 join关联1.1.1 内关联1.1.2 左关联1.1.3 右关联 1.2 Union合并 2. 缓存和checkpoint 1. 数据的关联与合并 1.1 join关联 students表数据: 1.1.1 内关联 内关联只返回两个 DataFrame 中在连接键上匹配的行。 # join 关联 from…

Python入门:轻松学会Python的*args和**kwargs

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Python传参 📒📝 *args📝 **kwargs📝 综合使用 *args 和 **kwargs📝 注意事项⚓️ 相关链接 ⚓️📖 介绍 📖 在你编写Python代码时,是否曾遇到过需要处理数量不定的参数的情况?许多刚Python入门的新手在面对这种…

VLAN概述

1.VLAN的概念 VLAN(Virtual Local Area Network,虚拟局域网)是一种将物理网络划分成多个逻辑网络的技术。 2.VLAN的作用和好处 2.1作用 划分广播域,控制广播消息传递范围 2.2好处 控制广播 增强网络安全性 简化网络管理 3.…

visio导出pdf公式变形问题杂谈

其实不会变形。 我自己的情况是直接用edge PDF阅读器打开pdf看到的是公式有变形(常见是字体、形状变了),但换一个pdf阅读器如adobe的就是正常的了 不过大家一般是用edge pdf阅读器直接打开查看,所以通过visio打印的方式导出pdf可…

若依框架中spring security的完整认证流程,及其如何使用自定义用户表进行登录认证,学会轻松实现二开,嘎嘎赚块乾

1)熟悉之前的SysUser登录流程 过滤器链验证配置 这里security过滤器链增加了前置过滤器链jwtFilter 该过滤器为我们自定义的,每次请求都会经过jwt验证 ok我们按ctrl alt B跳转过去来看下 首先会获取登录用户LoginUser 内部通过header键,获…