Go语言设计与实现 -- 接口

news2024/11/20 4:25:22

接口实际上是一个中间层,用于上下游的解耦,在框架和操作系统中,接口都随处可见,而Go语言将接口作为了内置类型,接下来,我们就来重点学习一下,Go语言的接口。

  • 将实现接口的结构体实例赋值给接口
  • 结构便可以调用其中的方法

Java的接口和Go的方式是完全不同的:

  • 在Java中,实现接口需要显式声明接口并实现所有方法
  • 在Go语言中,实现接口的所有方法就隐式实现了接口

Go语言只会在传递参数,返回参数,以及变量赋值的时候检查某个类型是否实现了接口。简而言之,就是在需要它的时候才会去检查

Go接口分为两种:

  • 空接口
  • 带有方法的接口

它与C语言的void *不一样,interface{}类型并不是任意类型。如果我们将类型转换成了interface{},变量在运行期间的类型也会随之发生变化,获取变量时会得到interface{}

接口和指针

来看几组代码:

type Duck interface {
	Walk()
}

type Cat struct{}

// 注意,指针
func (c *Cat) Walk() {
	fmt.Println("lxy")
}

func main() {
    // 接口赋值,指针、
    // 这里的&Cat{}变量能够隐式的指向的结构体
	var d Duck = &Cat{}
	d.Walk()
}

这一组接口赋值没有发生任何错误。

type Duck interface {
   Walk()
}

type Cat struct{}

// 值
func (c Cat) Walk() {
   fmt.Println("lxy")
}

func main() {
    // 指针
   var d Duck = &Cat{}
   d.Walk()
}

代码没有出现任何问题。

type Duck interface {
   Walk()
}

type Cat struct{}

func (c Cat) Walk() {
   fmt.Println("lxy")
}

func main() {
   var d Duck = Cat{}
   d.Walk()
}

这个代码也没有出现任何问题,接下来来看一下会出问题的代码:

在这里插入图片描述

为什么会发生这样的事情呢?

golang-interface-method-receive

  • 对于这张图的左侧而言,这意味着复制一个结构体指针,该指针与原来的指针指向相同且唯一的结构体,所以编译器可以对变量解引用获取指针指向的结构体。
  • 对于右侧的图而言,对于Cat{}来说,这意味着方法会接收一个全新的Cat{},这意味着walk()方法会接收一个全新的Cat{},所以编译器不会无中生有创建一个新指针;即使编译器可以创建新指针,这个指针指向的也不是最初调用改方法的结构体。

总结一下:Go语言中的指针类型在使用的时候会自动进行解引用,如果方法类型和传递的类型是一致的话,那么可以成功是毋庸置疑的,但是指针传给非指针的时候,指针会自动解引用成非指针之后完成复制,如果是非指针传递给指针的时候,那么这个操作就无法完成,Go语言不会自动的加上一个指针。

nil和non-nil

我们要记住一句话Go语言的接口类型不是任意类型。

我们接下来来看组代码:

type TestStruct struct{}

func NilOrNot(v interface{}) bool {
   return v == nil
}

func main() {
   var s *TestStruct
   fmt.Println(s == nil)    // true
   fmt.Println(NilOrNot(s)) // false
}

可以看到这一组的结果,为什么第二个打印是false呢?

调用NilOrNot的时候发生了隐式类型转换。除了向方法传入参数之外,变量的赋值也会触发隐式类型转换。在进行类型转换的时候,*TestStruct类型会转换成interface{}类型。转换后的变量不仅包含转换前的变量,还包含类型信息TestStruct,所以与nil不相等。

数据结构

Go根据结构是否包含一组方法将接口分成了两类:

  • 使用runtime.iface结构体表示包含方法的接口
  • 使用runtime.eface结构体表示不包含任何方法的interface{}

我们来看一下这两个结构体的实现:

type iface struct {
   tab  *itab
   data unsafe.Pointer
}
type eface struct {
   _type *_type
   data  unsafe.Pointer
}

可以看到第二个字段data都是一样的,它指向接口的数据。

紧接着,我们先来看一下eface_type结构体。

type _type struct {
    // 字段存储了类型占用的内存空间,为内存的空间分配提供信息
   size       uintptr
   ptrdata    uintptr 
    // 快速确定类型是否相等
   hash       uint32
   tflag      tflag
   align      uint8
   fieldAlign uint8
   kind       uint8
    // 用于判断当前类型的多个对象是否相等
   equal func(unsafe.Pointer, unsafe.Pointer) bool
   gcdata    *byte
   str       nameOff
   ptrToThis typeOff
}

这个结构体里面存放的是类型的元信息。

再来看一下itab结构体:

·face除了要存储动态类型但是信息之外,还要存储接口本身的信息,以及动态类型所实现的方法的信息,所以是这样的。

type itab struct {
   inter *interfacetype
   _type *_type
    // 对_type.hash的复制,当我们想将interface类型转换成具体类型的时候,可以使用该字段快速判断目标类型和具体类型的runtime._type是否相同
   hash  uint32
   _     [4]byte
   fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

可以看到这个结构体里面也有我们的_type结构体,代表它同样可以存储我们的数据类型。

在这里插入图片描述
在这里插入图片描述

我们来逐一分析一下这个结构体,第一个指针interfacetype这个存储着这个结构体类型自身的信息。

type interfacetype struct {
   typ     _type // 类型信息
   pkgpath name // 包路径名
   mhdr    []imethod // 结构方法集合
}

_type字段存储的是这个结构变量的动态类型的信息。

fun是动态类型已实现的接口方法的调用地址数组。

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

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

相关文章

(三)汇编语言——DOSBox

本篇主要用来介绍我们的实验平台——DOSBox的使用与调试,主要就是改一下窗口大小以及挂载,并且作为学习汇编实验的汇总,不定期更新。 下载与安装 这个可以到官网去下载,然后安装也很简单,就不介绍了,而且一…

力扣(LeetCode)1753. 移除石子的最大得分(C++\C)

贪心模拟 贪心思路 : 循环从石子数量最多的两堆取石子,直到有两堆以上(含两堆)空石子,维护取子次数,即是答案。贪心的正确性,暂无数学证明。直觉来看,这么做是对的。 CPP class Solution { public:int maximumScore…

设计模式之观察者模式

Observer design pattern 观察者模式的概念、观察者模式的结构、观察者模式的优缺点、观察者模式的使用场景、观察者模式的实现示例、观察者模式的源码分析 1、观察者模式的概念 观察者模式,又称为发布-订阅模式,即它定义了一种对象间一对多的依赖关系&…

spark 运行自带样例SparkPi、spark-examples报错

报错时我使用的环境如下: windows10中运行,非linux虚拟机 使用微软的Terminal软件进入powershell环境 scala 2.12.10 spark-3.1.1-bin-hadoop3.2 没有单独安装hadoop环境 java 8 注意一:该spark-3.1.1-bin-hadoop3.2在centos 7、树莓派4b官方…

2小时上车AI作画_NovelAI (学会能做游戏mod)

最近在打牌(杀戮尖塔真好玩),玩着突发奇想: 能不能?把游戏原画,通过AI作画,替换为二次元风格? 试试就逝逝...简单复盘下 一、部署"NovelAI" 本地部署【需要本地显卡】 …

Linux C 链接模块

静态链接 Linux 下静态库的创建和使用 1.编译静态库源码&#xff1a;gcc -c lib.c -o lib.o 2.生成静态库文件&#xff1a;ar -q lib.a lib.o 2.使用静态库编译&#xff1a;gcc main.c lib.a -o main.out #20-1.c #include <stdio.h>extern char* name(); extern int a…

Python 自动化测试(三): pytest 参数化测试用例构建

在之前的文章中主要分享了 pytest 的实用特性&#xff0c;接下来讲 Pytest 参数化用例的构建。 如果待测试的输入与输出是一组数据&#xff0c;可以把测试数据组织起来用不同的测试数据调用相同的测试方法。参数化顾名思义就是把不同的参数&#xff0c;写到一个集合里&#xff…

Mentor-dft 学习笔记 day46-Graybox OverviewTessent On-Chip Clock Controller(1)

graybox功能简化了分层设计中的扫描插入和ATPG处理过程&#xff0c;允许对子模块执行扫描和ATPG操作&#xff0c;然后允许在以下情况下使用该子模块的简化灰箱表示在下一个更高层次执行扫描和ATPG操作。由于子模块的灰盒表示仅包含最小数量的互连电路&#xff0c;因此在大型分层…

Oracle-在线重定义dbms_redefinition.sync_interim_table增量同步引发TX行锁问题

前言: 近期处理了一起用户使用在线重定义dbms_redefinition增量同步操作引发TX行锁的问题&#xff0c;用户在使用dbms_redefinition.sync_interim_table进行数据增量同步时&#xff0c;在线重定义的原表SQL语句出现了TX行锁等待问题 后面经过分析&#xff0c;发现产生TX行锁问…

短链接业务解决方案(附源码项目)

开源地址 https://github.com/lcy19930619/short-link 一个单节点短链接项目&#xff0c;有需要的拿去改改就行了&#xff0c;如果方便&#xff0c;可以帮忙点点star 什么是短链接 蓝色部分就是短链接 为什么要用短链接&#xff1f; 因为短信是按照字符去计算条数的&#x…

12月21日 OpenCV 实战基础学习笔记——背景建模、光流估计

文章目录前言一、背景建模1、帧差法2、混合高斯模型二、光流估计前言 本文为12月21日 OpenCV 实战基础学习笔记&#xff0c;分为两个章节&#xff1a; 背景建模&#xff1b;光流估计。 一、背景建模 1、帧差法 由于场景中的目标在运动&#xff0c;目标的影像在不同图像帧中…

Redis哨兵机制以及发布订阅

Redis哨兵机制1 哨兵Sentinel机制2 哨兵架构原理3 搭建哨兵架构4 通过springboot操作哨兵Redis发布订阅1 哨兵Sentinel机制 Sentinel&#xff08;哨兵&#xff09;是Redis 的高可用性解决方案&#xff1a;由一个或多个Sentinel 实例组成的Sentinel 系统可以监视任意多个主服务…

海格里斯HEGERLS深度解析|重型四向穿梭车的轨道换向组件及轨道系统

随着自动化仓储物流系统的广泛应用&#xff0c;物流设备也更趋于多样化&#xff0c;比如在货架轨道上可四向行走的穿梭车应运而生&#xff0c;重型四向穿梭车作为一种新型的物流存储设备&#xff0c;通常在轨道平面上有行走方向相互垂直的两个行走系统&#xff0c;通过两个行走…

gRPC学习Go版(一)

文章目录微服务入门gRPC是什么proto 服务定义gRPC 优势gRPC入门简单使用一元RPC服务流RPC客户流RPC双工流RPCgRPC底层原理RPC流长度前缀的消息分帧请求消息响应信息通信模式下的消息流微服务入门 现在的软件很少是一个孤立的单体应用运行的&#xff0c;相反更多是通过互联网连接…

玩以太坊链上项目的必备技能(错误处理以及异常-Solidity之旅十四)

错误处理 作为开发者的我们知道&#xff0c;我们所编写出来的程序难免会出现 bug &#xff0c;而要做的是捕获异常&#xff0c;给用户抛出一个友好地错误提示。 而在 Solidity 中&#xff0c;根据状态恢复异常来处理错误&#xff0c;该异常将撤销在当前调用中对状态所做的所有…

[思维模式-9]:《如何系统思考》-5- 认识篇 - 改变开环、组合逻辑的线性思考,实施闭环、时序逻辑的动态思考。

目录 第1章 因果关系 1.1 因果关系 1.2 因果关系的特点 1.3 因果关系的类型 第2章 线性思考遇到的问题&#xff1a;开环思维、组合逻辑 2.1 开环系统 2.2 组合逻辑 2.3 线性关系 2.4 什么是线性思维&#xff1a;线性因果关系 2.5 线性思维的数学本质 2.6 线性思维的…

自动化药房出药升降机选型设计

一、 运动规划、运动参数的确定 1、 运动参数计算 运动参数主要通过速度规划确定&#xff0c;速度规划采用直线速度特性&#xff0c;如图所示。 运动方程为&#xff1a; 2、 X方向的速度和加速度的估算 已知参数&#xff1a; X方向行程:1…

stream_component_open函数分析

stream_component_open() 函数主要作用是打开 音频流或者视频流 对应的解码器&#xff0c;开启解码线程去解码。 流程图如下&#xff1a; stream_component_open() 的函数定义如下&#xff1a; /* open a given stream. Return 0 if OK */ static int stream_component_open(…

K8S知识点及dashboard操作

1.什么是K8S&#xff1f; K8S是一组服务器集群&#xff0c;可以在集群的各个节点上运行特定的容器。 K8S所管理的是&#xff1a;集群节点上的容器 特性&#xff1a; 自我修复&#xff0c;弹性伸缩&#xff08;根据实时服务器的并打情况&#xff0c;增加或收缩容器数量&…

网络编程套接字Socket(通过两个用例,逐行注释,详细理解)干活满满建议收藏

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言1.分类1.流套接字2.数据报套接字3.原始套接字2.Socket通信模型 3.UDP套接字编程1. DatagramSocket API1.构造方法1.DatagramSocket()2.DatagramSocket(int port)…