广告
返回顶部
首页 > 资讯 > 后端开发 > GO >golang的接口怎么定义使用
  • 299
分享到

golang的接口怎么定义使用

2023-07-04 22:07:56 299人浏览 独家记忆
摘要

这篇文章主要讲解了“golang的接口怎么定义使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang的接口怎么定义使用”吧!在golang中,接口是一种类型,是用来将对方法进行一个收

这篇文章主要讲解了“golang的接口怎么定义使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang的接口怎么定义使用”吧!

在golang中,接口是一种类型,是用来将对方法进行一个收束,其作用是:1、作为方法的收束器,进行面向对象设计;2、作为各种数据的承载者,可以用来接收函数参数等。接口的定义语法“type 接口类型名 interface{方法名( 参数列表1 ) 返回值列表}”;当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

一、接口(interface)是什么

interface是一组method签名的组合,我们通过interface来定义对象的一组行为。

(注意method 和普通func的区别)

Interface是一种类型,和往常语言的接口不一样,它只是用来将对方法进行一个收束。然而正是这种收束,使GO语言拥有了基于功能的面向对象。

接口的主要功能:

作为方法的收束器,进行面向对象设计。

作为各种数据的承载者,可以用来接收函数参数等。

这也是,GO语言提倡面向接口编程

二、接口的定义使用

2.1定义

类似结构体

type 接口类型名 interface{    方法名1( 参数列表1 ) 返回值列表1    方法名2( 参数列表2 ) 返回值列表2    …}

当然这只是有方法的接口定义,面向数据的接口不用。

  • 接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。

  • 方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

  • 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略

2.2使用

一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表

//定义接口type FastfoodStore interface{    MakeHamberger()    MakeFriedChips()    MakeSoftDrink()}//定义结构体type KFC struct{}type HambergerKing struct{}//实现了接口中所有的方法func (kfc KFC) MakeHamberger(){    fmt.println("肯德基的汉堡")}func (kfc KFC) MakeFriedChips(){    fmt.println("肯德基的薯条")}func (kfc KFC) MakeSoftDrink(){    fmt.println("肯德基的饮料")}func (K *HambergerKing) MakeHameberger(){    fmt.println("汉堡王的汉堡")}func (K *HambergerKing) MakeFriedChips(){    fmt.println("汉堡王的薯条")}func (K *HambergerKing) MakeSoftDrink(){    fmt.println("汉堡王的饮料")}

我们可以看到不同于Java的接口显式实现,Go的语言是隐式实现的。

  • 在 Java 中:实现接口需要显式地声明接口并实现所有方法;

  • 在 Go 中:实现接口的所有方法就隐式地实现了接口;

那么GO语言是如何检查该类型是否是接口呢?

答:Go 语言只会在传递参数、返回参数以及变量赋值时才会对某个类型是否实现接口进行检查。从类型检查的过程来看,编译器仅在需要时才检查类型,类型实现接口时只需要实现接口中的全部方法,不需要像 Java 等编程语言中一样显式声明。

我们可以看到在上面实现接口的时候,KFC是用结构体对象实现的,而Hamberger king是通过指针实现的两者有什么不同呢?

答:区别在于我们初始化接口的时候

//结构体初始化和指针初始化var f faststore = KFC{}             //可以通过编译var f faststore = &KFC{}            //可以通过编译var f faststore = HambergerKing{}    //无法通过编译var f faststore = &HambergerKing{}    //可以通过编译

所以在我们使用指针进行实现,结构体初始化时,为啥不行呢?

答:Go 语言在传递参数时都是传值的。

golang的接口怎么定义使用

如上图所示,无论上述代码中初始化的变量指针还是结构体,使用 调用方法时都会发生值拷贝:

如上图左侧,对于 &HambergerKing{} 来说,这意味着拷贝一个新的 &HambergerKing{} 指针,这个指针与原来的指针指向一个相同并且唯一的结构体,所以编译器可以隐式的对变量解引用(dereference)获取指针指向的结构体;
如上图右侧,对于 HambergerKing{} 来说,这意味着方法会接受一个全新的 HambergerKing{},因为方法的参数是*HambergerKing,编译器不会无中生有创建一个新的指针;即使编译器可以创建新指针,这个指针指向的也不是最初调用该方法的结构体;
上面的分析解释了指针类型的现象,当我们使用指针实现接口时,只有指针类型的变量才会实现该接口;当我们使用结构体实现接口时,指针类型和结构体类型都会实现该接口。当然这并不意味着我们应该一律使用结构体实现接口,这个问题在实际工程中也没那么重要,在这里我们只想解释现象背后的原因。

在上面我们说过,interface有两种用法,现在介绍了其中一种就是作为方法的收束器。那么第二种就是作为数据的承载者

2.3 数据承载者

作为数据容器时,接口就是一个“空”接口,这个空来形容没有Method。空interface(interface{})不包含任何的method,正因为如此,所有的类型都实现了空interface。空interface对于描述起不到任何的作用(因为它不包含任何的method),但是空interface在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。

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

我们尝试从底层实现来解释两种用法的不同,你会好理解一些。Go 语言使用 runtime.iface 表示第一种接口,使用 runtime.eface 表示第二种不包含任何方法的接口 interface{},两种接口虽然都使用 interface 声明,但是由于后者在 Go 语言中很常见,所以在实现时使用了特殊的类型。

golang的接口怎么定义使用

空接口作为函数的参数

使用空接口实现可以接收任意类型的函数参数。

// 空接口作为函数参数func show(a interface{}) {    fmt.Printf("type:%T value:%v\n", a, a)}

空接口作为map的值

使用空接口实现可以保存任意值的字典。

// 空接口作为map值    var studentInfo = make(map[string]interface{})    studentInfo["name"] = "Wilen"    studentInfo["age"] = 18    studentInfo["married"] = false    fmt.Println(studentInfo)//gin框架的gin.H{}

三、关于接口类型转换

interface 可以存储所有的值,那么自然会涉及到类型转换这个话题。与此同时,我们也将在这节细说类型转换中,因为结构体实现和结构体指针实现的接口的异同。

3.1结构体指针实现接口

//我们仍然运用上面快餐店的例子type Store interface{    MakeHamberger()}type KFC struct{    name string}func (k *KFC) MakeHamberger(){    fmt.println(k.name+"制作了一个汉堡")}func main(){    var s store = &KFC{name:"东街店"}    store.MakeHamberger()}

这里将上述代码生成的汇编指令拆分成三部分分析:

1.结构体 KFC 的初始化;

KFC的初始化又可以分为下面几步:

  • 获取 KFC 结构体类型指针并将其作为参数放到栈上;

  • 通过 CALL 指定调用 runtime.newobject函数,这个函数会以 KFC 结构体类型指针作为入参,分配一片新的内存空间并将指向这片内存空间的指针返回到 SP+8 上;

  • SP+8 现在存储了一个指向 KFC 结构体的指针,我们将栈上的指针拷贝到寄存器 DI 上方便操作;

  • 由于 Cat 中只包含一个字符串类型的 Name 变量,所以在这里会分别将字符串地址 &"东街店" 和字符串长度 6 设置到结构体上。

golang的接口怎么定义使用

2.赋值触发的类型转换过程;

因为 KFC 结构体的定义中只包含一个字符串,而字符串在 Go 语言中总共占 16 字节,所以每一个 KFC 结构体的大小都是 16 字节。初始化 KFC 结构体之后就进入了将 *KFC 转换成 Store 类型的过程了:

类型转换的过程比较简单,Store 作为一个包含方法的接口,它在底层使用 [runtime.iface] 结构体表示。runtime.iface 结构体包含两个字段,其中一个是指向数据的指针,另一个是表示接口和结构体关系的 tab 字段,我们已经通过上一段代码 SP+8 初始化了 KFC 结构体指针,这段代码只是将编译期间生成的 runtime.itab 结构体指针复制到 SP 上:

golang的接口怎么定义使用

到这里,我们会发现 SP ~ SP+16 共同组成了 runtime.iface 结构体。

3.调用接口的方法 Quack();

栈上的这个 runtime.iface 也是 MakeHamberger() 方法的第一个入参。通过CALL()完成方法的调用。

3.2 结构体实现接口

//我们仍然运用上面快餐店的例子type Store interface{    MakeHamberger()}type KFC struct{    name string}func (k KFC) MakeHamberger(){    fmt.println(k.name+"制作了一个汉堡")}func main(){    var s store = KFC{name:"东街店"}    store.MakeHamberger()}

如果我们在初始化变量时使用指针类型 &KFC{Name: "东街店"} 也能够通过编译,不过生成的汇编代码和上一节中的几乎完全相同,所以这里也就不分析这个情况了。

初始化 KFC 结构体;

在栈上初始化 KFC 结构体,而上一节的代码在堆上申请了 16 字节的内存空间,栈上只有一个指向 KFC 的指针。

完成从 KFC 到 Store 接口的类型转换;

初始化结构体后会进入类型转换的阶段,编译器会将 go.itab."".KFC,"".Store 的地址和指向 KFC 结构体的指针作为参数一并传入 runtime.convT2I 函数:这个函数会获取 runtime.itab 中存储的类型,根据类型的大小申请一片内存空间并将 elem 指针中的内容拷贝到目标的内存中:

func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {    t := tab._type    x := mallocGC(t.size, t, true)    typedmemmove(t, x, elem)    i.tab = tab    i.data = x    return}

runtime.convT2I 会返回一个 runtime.iface,其中包含 runtime.itab 指针和 KFC 变量。当前函数返回之后,main 函数的栈上会包含以下数据:

golang的接口怎么定义使用

SP 和 SP+8 中存储的 runtime.itab 和 KFC 指针是 runtime.convT2I 函数的入参,这个函数的返回值位于 SP+16,是一个占 16 字节内存空间的 runtime.iface 结构体,SP+32 存储的是在栈上的 KFC 结构体,它会在 runtime.convT2I 执行的过程中拷贝到堆上。

3.3类型断言

如何将一个接口类型转换成具体类型?

x.(T)

非空接口

func main() {    var c Store = &KFC{Name: "东街店"}    switch c.(type) {    case *KFC:        kfc := c.(*KFC)        kfc.MakeHamberger()    }}

因为 Go 语言的编译器做了一些优化,所以代码中没有runtime.iface 的构建过程,不过对于这一节要介绍的类型断言和转换没有太多的影响。

switch语句生成的汇编指令会将目标类型的 hash 与接口变量中的 itab.hash 进行比较

空接口

func main() {    var c interface{} = &KFC{Name: "东街店"}    switch c.(type) {    case *KFC:        kfc := c.(*KFC)        kfc.MakeHamberger()    }}

上述代码会在类型断言时就不是直接获取变量中具体类型的 runtime._type,而是从 eface._type 中获取,汇编指令仍然会使用目标类型的 hash 与变量的类型比较.

感谢各位的阅读,以上就是“golang的接口怎么定义使用”的内容了,经过本文的学习后,相信大家对golang的接口怎么定义使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

您可能感兴趣的文档:

--结束END--

本文标题: golang的接口怎么定义使用

本文链接: https://www.lsjlt.com/news/347970.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • golang的接口怎么定义使用
    这篇文章主要讲解了“golang的接口怎么定义使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“golang的接口怎么定义使用”吧!在golang中,接口是一种类型,是用来将对方法进行一个收...
    99+
    2023-07-04
  • Golang接口的定义与空接口及断言怎么使用
    这篇文章主要讲解了“Golang接口的定义与空接口及断言怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang接口的定义与空接口及断言怎么使用”吧!1. Golang中的接口在G...
    99+
    2023-07-06
  • Golang接口的定义与空接口及断言的使用示例
    目录1. Golang中的接口2. 为什么要使用接口3. 定义一个Usber接口(从下往上转换)4. 空接口1. 空接口说明2. 空接口作为函数的参数3. 切片实现空接口4. map...
    99+
    2023-05-15
    Go接口的定义 Go空接口 Go断言
  • typeScript的interface接口怎么定义使用
    这篇“typeScript的interface接口怎么定义使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“typeScri...
    99+
    2023-06-29
  • TypeScript怎么定义接口
    这篇文章主要讲解了“TypeScript怎么定义接口”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“TypeScript怎么定义接口”吧!接口的作用:接口,英文:interface,其作用可以...
    99+
    2023-06-20
  • C#接口怎么定义
    这篇文章主要介绍“C#接口怎么定义”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#接口怎么定义”文章能帮助大家解决问题。C# 接口(Interface)接口定义了所有类继承接口时应遵循的...
    99+
    2023-06-17
  • java SPI怎么定义接口
    这篇文章主要介绍了java SPI怎么定义接口的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java SPI怎么定义接口文章都会有所收获,下面我们一起来看看吧。使用说明服务提供者提供接口的具体实现后,在jar包...
    99+
    2023-06-30
  • C#中怎么定义接口
    C#中怎么定义接口,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C#接口定义之声明接口声明接口在语法上和声明抽象类完全相同,例如这里有一个银行账户的接口:public&nb...
    99+
    2023-06-17
  • Java抽象类与接口怎么定义使用
    这篇文章主要介绍“Java抽象类与接口怎么定义使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java抽象类与接口怎么定义使用”文章能帮助大家解决问题。1.对象的比较两个对象要进行比较之前,我们首...
    99+
    2023-06-30
  • Spring Boot中怎么定义接口
    Spring Boot中怎么定义接口,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。我们在 Controller 中定义接口的时候,一般都是像下面这样:@GetMapping...
    99+
    2023-06-15
  • 怎么在java中定义接口
    今天就跟大家聊聊有关怎么在java中定义接口,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Jav...
    99+
    2023-06-14
  • Golang中的Struct怎么定义和使用
    本篇内容主要讲解“Golang中的Struct怎么定义和使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中的Struct怎么定义和使用”吧!Go语言中提供了对struct的支持;s...
    99+
    2023-07-04
  • Golang中的切片怎么定义使用
    这篇文章主要介绍了Golang中的切片怎么定义使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang中的切片怎么定义使用文章都会有所收获,下面我们一起来看看吧。1.切片的定义从上一节我们知道,因为数组的...
    99+
    2023-07-04
  • Golang开发之接口怎么使用
    今天小编给大家分享一下Golang开发之接口怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Golang的接口是什么在...
    99+
    2023-07-05
  • java接口的修饰符怎么定义
    这篇文章主要介绍了java接口的修饰符怎么定义的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java接口的修饰符怎么定义文章都会有所收获,下面我们一起来看看吧。java接口的修饰符可以是abstract和fin...
    99+
    2023-07-04
  • golang中的空接口怎么用
    这篇文章给大家分享的是有关golang中的空接口怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、空接口Golang 中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口。空接口表示,没有任何约束,...
    99+
    2023-06-14
  • java接口怎么定义与实现
    今天小编给大家分享一下java接口怎么定义与实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。本教程操作环境:windows...
    99+
    2023-06-30
  • Golang中的数组怎么定义和使用
    这篇文章主要介绍“Golang中的数组怎么定义和使用”,在日常操作中,相信很多人在Golang中的数组怎么定义和使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang中的数组怎么定义和使用”的疑惑有所...
    99+
    2023-07-04
  • Golang中的方法怎么定义和使用
    这篇文章主要介绍“Golang中的方法怎么定义和使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Golang中的方法怎么定义和使用”文章能帮助大家解决问题。方法语法在Golang中,方法定义的语法...
    99+
    2023-07-05
  • JavaSE中抽象类与接口怎么定义及使用
    这篇文章主要介绍“JavaSE中抽象类与接口怎么定义及使用”,在日常操作中,相信很多人在JavaSE中抽象类与接口怎么定义及使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaSE中抽象类与接口怎么定义...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作