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…

微服务之间是如何独立通讯的?

前言 微服务架构是一种将一个应用程序拆分成多个小型、独立的服务的架构。在微服务架构中,各个服务之间需要进行通信来完成数据交互和业务处理。本文将详细介绍微服务之间如何独立通信的。 微服务之间独立通讯主要依靠定义清晰的API协议、使用轻量级交互机制、以及…

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类知识:工作和面试不常用,代码不…

深度学习相关知识点

epoch/batch/batch_size的关系 Epoch:模型在整个数据集上完成一次训练。一个epoch后,模型已经看过所有的训练数据,执行了正向传播和反向传播。通常训练需要多个epoch,模型才能逐步学习和收敛。Batch:由于在深度学习中…

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

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

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

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

Python 基础之条件语句

一、条件语句简介 在Python中,条件语句用于根据不同的条件执行不同的代码块。这使得程序能够根据特定的情况做出决策,并执行相应的操作。 二、if 语句 if语句是最基本的条件语句。它用于检查一个条件,如果条件为真,则执行特定的代…

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

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

利用sessionStorage收集用户访问信息,然后传递给后端

这里只是简单的收集用户的停留时间、页面加载时间、当前页面URL及来源页面&#xff0c;以做示例 <html><head><meta http-equiv"content-type" content"text/html; charsetUTF-8"/><title>测试sessionStorage存储用户访问信息<…

基于深度学习的设备异常检测与预测性维护

基于深度学习的设备异常检测与预测性维护是一项利用深度学习技术分析设备运行数据&#xff0c;实时检测设备运行过程中的异常情况&#xff0c;并预测未来可能的故障&#xff0c;以便提前进行维护&#xff0c;防止意外停机和生产中断。它在工业领域应用广泛&#xff0c;特别是在…

使用docker搭建lnmp运行WordPress

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

路由通信 的 VLAN技术

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