Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >interface引发的事件真相

interface引发的事件真相

作者头像
李海彬
发布于 2018-03-27 03:49:15
发布于 2018-03-27 03:49:15
70700
代码可运行
举报
文章被收录于专栏:Golang语言社区Golang语言社区
运行总次数:0
代码可运行
流动的水没有形状,漂流的风找不到踪迹,一切代码都了然于心,我们在写代码的时候,总是有一种思维定式陪伴左右,在对事物做判断的时候,往往这种思维定式会往正向或反向做推动作用,在开发的过程中如果不小心忽略,往往就是埋下了陷阱,以下代码是大多数新手会遇到的坑,
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main



import (

        "fmt"

)



type People interface {

        Name() string

}

type Student struct{ name string }



func (stu *Student) Name() string {

        return stu.name

}



func getPeople() People {

        var stu *Student

        return stu

}



func main() {

        if getPeople() == nil {

                fmt.Println("AAAAA")

        } else {

                fmt.Println("BBBBB")

        }

}

上面的代码输出什么那?有些人会认为打印AAAAA,因为他们会认为getPeople方法里面stu是nil 所以返回的就是nil,这样想就大错特错,因为虽然返回的stu是nil 但是函数返回时People接口的结构的本身并不是nil,在我们不了解interface内部结构之前请往下看。

为什么我会选择去写一个关于interface的文章那,我认为他在go语言里面有这非常重要的地位,仅次于goroutine和channel的地位,我在未接触go之前一直从事于c#的开发,接口对我来说就是不同组件之间的契约,对这个契约强制你必须去继承接口,而go语言的设计就非常轻巧,只要实现了接口所要求的所有函数即可,go中的接口分为两种一种是空的接口类似这样:

  1. var in interface{}

例外一种是非空的接口即在接口内部声明了一些方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type People interface {

        Name() string

}

接下来我就根据上面的例子来对比一下空接口和非空接口内部结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type eface struct {          //空接口

        _type *_type         //类型信息

        data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)

}

type iface struct {          //带有方法的接口

        tab  *itab           //存储type信息还有结构实现方法的集合

        data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)

}

eface包含一个类型信息,可以为reflect提供帮助

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type _type struct {

        size       uintptr  //类型大小

        ptrdata    uintptr  //前缀持有所有指针的内存大小

        hash       uint32   //数据hash值

        tflag      tflag    

        align      uint8    //对齐

        fieldalign uint8    //嵌入结构体时的对齐

        kind       uint8    //kind 有些枚举值kind等于0是无效的

        alg        *typeAlg //函数指针数组,类型实现的所有方法

        gcdata    *byte

        str       nameOff

        ptrToThis typeOff

}

iface比eface 中间多了一层itab结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type itab struct {

        inter  *interfacetype  //接口类型

        _type  *_type          //结构类型

        link   *itab           

        bad    int32

        inhash int32      

        fun    [1]uintptr      //可变大小 方法集合

}

itab 存储_type信息和[]fun方法集,从上面的结构我们就可得出,因为data指向了nil 并不代表interface 是nil,所以返回值并不为空,这里的fun(方法集)定义了接口的接收规则,在编译的过程中需要验证是否实现接口,接口的具体细节你可以阅读Go Data Structures: Interfaces

接下来是第二个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main



import (

        "fmt"

)



type People interface {

        Speak(string) string

}



type Stduent struct{}



func (stu *Stduent) Speak(think string) (talk string) {

        if think == "bitch" {

                talk = "You are a good boy"

        } else {

                talk = "hi"

        }

        return

}



func main() {

        var peo People = Stduent{}

        think := "bitch"

        fmt.Println(peo.Speak(think))

}

上面的代码是不能编译过去的,会提示没有实现该接口,只要我们把var peo People = Stduent{}修改为var peo People = &Stduent{}就可以了,为什么会有这种限制,

这是因为接口定义不规定实现者是否应该使用指针接收还是值接收实现接口。当使用接口时,不能保证底层类型是值还是指针。我们上面的例子中,我们定义了指针接受方法,修改为值接受方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (stu Stduent) Speak(think string) (talk string) {

        if think == "bitch" {

                talk = "You are a good boy"

        } else {

                talk = "hi"

        }

        return

}

我们再次运行打印:

  1. You are a good boy

通过上面测试我们得出一个结论使用值传递方法,接口赋值使用var peo People = Stduent{}或者var peo People = &Stduent{},如果使用指针作为参数传递,则只能使用var peo People = &Stduent{},正是由于interface的灵活性,可以使用golang实现多态的特性,所以我们更要对interface多做深入了解。(本文未来可能会做一些细微的调整)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Golang中interface内部构造与面试真题分析
那么,满足上述3个条件,就可以产生多态效果,就是,父类指针可以调用子类的具体方法。
brookwang
2022/06/24
5820
Golang中interface内部构造与面试真题分析
【Golang语言社区】Golang语言面试题
最近在很多地方看到了golang的面试题,看到了很多人对Golang的面试题心存恐惧,也是为了复习基础,我把解题的过程总结下来。
李海彬
2018/03/07
3.9K2
【Golang语言社区】Golang语言面试题
Go interface 原理剖析--类型转换
可能你看过的 interface 剖析的文章比较多了,这些文章基本都是从汇编角度分析类型转换或者动态转发。不过随着 Go 版本升级,对应的 Go 汇编也发生了巨大的变化,如果单从汇编角度去分析 interface 变的非常有难度,本篇文章我会从内存分配+汇编角度切入 interface,去了解 interface 的原理。
haohongfan
2021/08/20
7880
真的理解go interface了吗?
Go 语言中的接口是一组方法的签名,它是 Go 语言的重要组成部分。简单的说,interface是一组method签名的组合,我们通过interface来定义对象的一组行为。interface 是一种类型,定义如下:
Golang梦工厂
2022/07/08
2820
深入理解 go interface
在 go 里面通过 interface 实现了泛型、多态等面相对象特性, 那么在 go 的 interface 到底是什么
leobhao
2024/04/01
1230
Go-接口interface底层实现
Go语言中的接口类型会根据是否包含一组方法而分成两种不同的实现,分别为包含一组方法的iface结构体和不包含任何方法的eface结构体。我们将从这两个结构的底层数据结构说起,然后在interface编译时具体类型赋值给接口时是如果进行转换的。
小许code
2023/02/27
6540
Go-接口interface底层实现
【转】Go Interface 源码剖析
源网址:http://legendtkl.com/2017/07/01/golang-interface-implement/
lpxxn
2018/08/01
9100
Golang的interface
由于golang中说interface的文章太多了,很多都已经说的很细节了,所以我再说感觉也有点难。于是总结出几个关键问题,供你参考,如果能做到准确无误有理有据的回答,那么interface应该是没有问题了。
LinkinStar
2022/09/01
3180
GO系列(2)-interface特性
说明struct,在调用方法的时候,值类型既可以调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法
爽朗地狮子
2022/10/20
2840
Golang数据结构之Interface
除了了与基础性能息息相关的网络和内存管理之外,Golang 给人印象最深的一个特性就是 Inerface 数据结构了,Interface 距离业务系统非常近,其独特的静态编译,动态检测的类型定义方式为提供了非常好的编程灵活性,大大简化了业务系统设计的复杂程度。
thierryzhou
2022/12/20
3980
golang 反射的实现原理
此前的文章中,我们看到 golang 如何实现面向对象的封装: 通过 GoLang 实现面向对象思想
用户3147702
2022/06/27
1.6K1
golang 反射的实现原理
深度解密Go语言之关于 interface 的 10 个问题
这次文章依然很长,基本上涵盖了 interface 的方方面面,有例子,有源码分析,有汇编分析,前前后后写了 20 多天。洋洋洒洒,长篇大论,依然有些东西没有涉及到,比如文章里没有写到反射,当然,后面会单独写一篇关于反射的文章,这是后话。
梦醒人间
2019/05/21
9920
Go 接口:nil接口为什么不等于nil?
Go 语言核心团队的技术负责人 Russ Cox 也曾说过这样一句话:“如果要从 Go 语言中挑选出一个特性放入其他语言,我会选择接口”,这句话足以说明接口这一语法特性在这位 Go 语言大神心目中的地位。
贾维斯Echo
2023/11/09
3090
Go 接口:nil接口为什么不等于nil?
Golang 基础:接口使用、实现原理(eface iface)和设计模式
本文是我学习 Go Tour 和 Go 语言第一课 接口相关章节的笔记,如有理解不当之处,恳请留言指出,感谢!
张拭心 shixinzhang
2022/05/10
6210
Golang 基础:接口使用、实现原理(eface iface)和设计模式
golang 源码分析(28) interface 类型推断、反射
 Go语言被定义为一门系统编程语言,与C语言一样通过编译器生成可直接运行的二进制文件。这一点与Java,PHP,Python等编程语言存在很大的不同,这些语言都是运行在基于C语言开发的虚拟机上,如果想深入了解运行原理只需要看懂对应的C语言开发的虚拟机(绝大部分程序员应该都对C语言有基本的了解)。但是如果想深入学习Go语言,就需要对基本的汇编指令和语法有一定的了解(通过汇编可以了解到编译器到底做了什么工作)。  通过下面的例子简单了解如何通过汇编来了解Go语言的运行原理。编辑一个go文本call_function.go,输入如下代码:
golangLeetcode
2022/08/02
8060
golang 源码分析(28) interface 类型推断、反射
Go 神坑 1 —— interface{} 与 nil 的比较
interface 是 Go 里所提供的非常重要的特性。一个 interface 里可以定义一个或者多个函数,例如系统自带的io.ReadWriter的定义如下所示:
恋喵大鲤鱼
2021/12/06
5.2K1
Go 神坑 1 —— interface{} 与 nil 的比较
Golang Interface详解(下)
  在Go语言中,iface和eface是表示接口类型和空接口类型的内部数据结构。
Se7en258
2023/05/18
3360
Golang Interface详解(下)
理解Golang的nil
golang的interface是一种内置类型,严格来讲它算是goalng提供的一种语法糖,辅助编码用的,它在运行时会转换成两种类型(位于包/usr/local/go/src/runtime/runtime2.go中):
chandlerpan
2022/07/12
6000
手摸手Go 接口与反射
Go是强类型/静态类型语言,每个变量在编译时就已经确定是哪种静态类型。反射(reflection)是程序在运行时可以访问、检测、修改自身状态或行为的一种能力。在Java出现后迅速流行起来的概念,Go也提供了这种在运行时更新、检查变量值、调用变量的方法和变量支持的内在操作的机制,一定程度上弥补了静态语言在动态行为上的不足。
用户3904122
2022/06/29
4200
手摸手Go 接口与反射
深入理解Go切片
上述过程涉及两个问题,一是函数传接口或者切片类型的参数到底是传值还是传引用,一是切片转接口发生了什么。
用户4766018
2022/08/19
1890
相关推荐
Golang中interface内部构造与面试真题分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档