前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang Interface详解(下)

Golang Interface详解(下)

作者头像
Se7en258
发布2023-05-18 15:10:32
2320
发布2023-05-18 15:10:32
举报
文章被收录于专栏:Se7en的架构笔记Se7en的架构笔记

iface和eface的区别

  在Go语言中,iface和eface是表示接口类型和空接口类型的内部数据结构。

  iface表示一个具体的接口类型,包含了指向接口表的指针和指向数据的指针。接口表中存储了该接口类型的方法集信息,数据指针则指向实现了该接口的具体类型的值。

  eface则是一个空接口类型,包含了指向类型信息的指针和指向数据的指针。它可以表示任何类型的值。

  最大的区别在于 iface 描述的接口包含方法,而 eface 则是不包含任何方法的空接口:interface{}。   从源码层面看一下:

代码语言:javascript
复制
type iface struct {
    tab  *itab
    data unsafe.Pointer
}

type eface struct {
    _type *_type
    data  unsafe.Pointer

  iface 内部维护两个指针,tab 指向一个 itab 实体, 它表示接口的类型以及赋给这个接口的实体类型。data 则指向接口具体的值,一般而言是一个指向堆内存的指针。

  相比 iface,eface 就比较简单了。只维护了一个 _type 字段,表示空接口所承载的具体的实体类型。data 描述了具体的值。

接口的动态类型和动态值是什么

  从前面iface源码里可以看到:iface包含两个字段:tab 是接口表指针,指向类型信息;data 是数据指针,则指向具体的数据。它们分别被称为动态类型和动态值。

  • 接口类型和nil做比较

  首先明确一下接口值包括动态类型和动态值。接口值的零值是指动态类型和动态值都为 nil。当仅且当这两部分的值都为 nil 的情况下,这个接口值就才会被认为 接口值 == nil。

  让我们看一个例子:

代码语言:javascript
复制
package main

import "fmt"

type Coder interface {
 code()
}

type Gopher struct {
 name string
}

func (g Gopher) code() {
 fmt.Printf("%s is coding\n", g.name)
}

func main() {
 var c Coder
 fmt.Println(c == nil)  //true
 fmt.Printf("c: %T, %v\n", c, c)

 var g *Gopher
 fmt.Println(g == nil) //true

 c = g
 fmt.Println(c == nil) //false
 fmt.Printf("c: %T, %v\n", c, c)
}

  结果如下:

  一开始,c 的 动态类型和动态值都为 nil,g 也为 nil,当把 g 赋值给 c 后,c 的动态类型变成了 *main.Gopher,仅管 c 的动态值仍为 nil,但是当 c 和 nil 作比较的时候,结果就是 false 了。

  • 类型转换和断言的区别

  我们知道,Go 语言中不允许隐式类型转换,也就是说 = 两边,不允许出现类型不相同的变量。

  类型转换、类型断言本质都是把一个类型转换成另外一个类型。不同之处在于,类型断言是对接口变量进行的操作。

  • 类型转换

  类型转换是将一个变量的类型转换为另一个类型。在 Go 中,类型转换使用如下语法:

代码语言:javascript
复制
//类型转换语法
destinationType(variable)

// 例如:将float64类型的变量转换为int类型
var myFloat float64 = 3.14
var myInt int
myInt = int(myFloat)

注意,当进行类型转换时,可能会丢失一些信息(例如,将浮点数转换为整数时,小数部分将被舍去)。

  • 类型断言

  类型断言用于在接口类型和具体类型之间进行转换。类型断言的语法如下:

代码语言:javascript
复制
value, ok := interfaceVariable.(ConcreteType)

//如果断言成功,ok 的值将为 true,并且 value 将包含接口变量的具体类型值。如果断言失败,ok 的值将为 false,并且 value 将为具体类型的零值。

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

//你可以使用类型断言来检查一个 Shape 类型的变量是否包含一个 Circle 类型的值:
func main() {
    var myShape Shape
    myShape = Circle{Radius: 5}

    if circle, ok := myShape.(Circle); ok {
        fmt.Println("The shape is a circle with radius", circle.Radius)
    } else {
        fmt.Println("The shape is not a circle")
    }
}

参考资料

【有汇编分析,不错】http://legendtkl.com/2017/07/01/golang-interface-implement/

【interface 源码解读 很不错 包含反射】http://wudaijun.com/2018/01/go-interface-implement/

【类型转换和断言】https://www.cnblogs.com/zrtqsk/p/4157350.html

【断言】https://studygolang.com/articles/11419

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

本文分享自 Se7en的架构笔记 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • iface和eface的区别
  • 接口的动态类型和动态值是什么
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档