详解Golang中interface{}的注意事项
作者:阿兵云原生 发布时间:2024-05-09 09:30:59
interface {} 可以用于模拟多态
xdm 咱们写一个简单的例子,就举动物的例子
写一个 Animal 的接口,类似于 java 里面的抽象类 ,Animal 的接口 中有 2 个方案待实现
写一个 Cat 来继承 Animal , 实现 Eat 方法和 Drink 方法
动物都有吃和喝的行为,小猫吃的行为是吃鱼,小猫的喝的行为是喝可乐
最后在主函数中,使用父类的指针,来指向子类的实例化的一个子类地址
type Animal interface {
Eat(string) string
Drink(string) string
}
type Cat struct{}
func (c *Cat) Eat(food string) string {
if food != "fish" {
return "i dislike"
} else {
return "i like"
}
}
func (c *Cat) Drink(drink string) string {
if drink == "coke" {
return "i love"
}else{
return "abandon"
}
}
func main(){
var a Animal = &Cat{}
fmt.Println(a.Eat("fish"))
fmt.Println(a.Drink("water"))
}
看到上述代码,会不会有这样的疑问,命名是 &Cat{}
是取地址的,为什么 var a Animal
不写成指针呢?
这里需要注意,Animal 本身是 接口类型,自身就是一个指针
运行上述代码查看效果
# go run main.go
i like
abandon
没有毛病,小猫眯爱吃鱼,不爱喝水
interface{} 需要注意空和非空的情况
什么叫做空的 interface{} , 什么又叫做非空的 interface{} 呢?
咱们还是用上面的例子, 添加一个 testInterface 函数
,来实践一下
func testInterface() Animal {
var c *Cat
return c
}
func main() {
test := testInterface()
if test == nil {
fmt.Println("test is nil")
} else {
fmt.Println("test is not nil")
}
}
可以猜猜看,上面这个小案例会输出什么结果
理论上来看,testInterface
函数中我们只是创建了一个 Cat 指针,并没有赋值,因此默认是一个零值,因此会是一个 nil,那么 return 的时候,应该也是 return nil 才对吧,因此按照代码的逻辑来说应该是输出 test is nil
执行上述代码后,查看结果
# go run main.go
test is not nil
看到上面的结果,是不是觉得很奇怪,和自己的预期不一致
没关系,之前的文章我们说到过,觉得一个技术点奇怪,不是我们所期望的效果,原因是我们对其原理不够了解,不够熟悉
现在先来回答一下上面的问题
空接口:意思是没有方法的接口,interface{} 源码中表示为 eface 结构体
非空接口:表示有包含方法的接口 , interface{} 源码中表示为 iface 结构体
暂时先来直接介绍源码中的结构体
iface结构体,非空
type iface struct {
tab *itab
data unsafe.Pointer
}
type itab struct {
inter *interfacetype
_type *_type
link *itab
hash uint32 // copy of _type.hash. Used for type switches.
bad bool // type does not implement interface
inhash bool // has this itab been added to hash?
unused [2]byte
fun [1]uintptr // variable sized
}
tab
指的是具体的类型信息,是一个 itab 结构,结构中成员如上,这里面包含的都是借口的关键信息,例如 hash 值 ,函数指针,等等,后续详细剖析 interface{} 原理的时候再统一说
data
具体的数据信息
eface结构体
type eface struct {
_type *_type
data unsafe.Pointer
}
type _type struct {
size uintptr // 表示的是 类型的大小
ptrdata uintptr // 值的是前缀指针的内存大小
hash uint32 // 计算数据的 hash 值
tflag tflag
align uint8 // 进行内存对齐的
fieldalign uint8
kind uint8
alg *typeAlg
gcdata *byte
str nameOff
ptrToThis typeOff
}
_type
类型信息,和上面的 非空接口类似 , 这个_type 类型决定下面的 data 字段如何去解释数据
data
具体的数据信息
看到这里,细心的 xdm 是不是就可以看出来,我们上面写的 Animal 接口,其实是一个非空接口,因为里面有包含方法,所以他的底层是一个 iface 结构体 ,非空接口
那么初始化的一个空指针 c ,实际上是 iface 结构体里面的 data 字段为空而已,数据为空而已,但是 iface 这个结构体自己不是空的,所以上述代码走的逻辑是 test is not nil
这里顺带说一下,golang 中,还有哪些数据结构是和 nil 比较是否为零值,这个点我们也可以看看源码
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
源码中有说到,可以对 指针,通道,函数,接口,map,切片类型使用 nil
好了,本次就到这里,知识点要用起来才有价值
来源:https://segmentfault.com/a/1190000043506591


猜你喜欢
- 1、主从同步原理主从同步架构图(异步同步)这是最常见的主从同步架构主从同步流程(异步同步)主库把数据变更写入binlog文件从库I/O线程发
- global.asa<SCRIPT LANGUAGE=VBScript RUNAT=Server>Sub&n
- 1.概述随着人工智能技术的不断发展,越来越多的AI产品被应用到各个领域,其中最具代表性的莫过于人工智能语言模型。语言模型是一种可以通过学习大
- 本文实例为大家分享了python实现学生通讯录管理系统的具体代码,供大家参考,具体内容如下功能模块分析:1.首页(菜单功能)2.添加学生3.
- reflow是个神奇的东西,之前Realazy说到过这个reflow,我摘出其中的重点:在CSS规范中有一个渲染对象的概念,通常用一个盒子(
- 引言对 axios 二次封装,更加的可配置化、扩展性更加强大灵活通过 class 类实现,class 具备更强封装性(封装、继承、多态),通
- 本节重点掌握Cpython的GIL解释器锁的工作机制掌握GIL与互斥锁掌握Cpython下多线程与多进程各自的应用场景本节时长需控制在45分
- 1、前言接上节,我们初步体验了layui-vue的用法。相比其他ui框架,layui-vue的数据结构显得不是非常友好,但是经过数据拼凑也是
- python中注释在python中的注释一般分为单行注释、多行注释以及文档注释。注释描述在实际开发过程中,有效的代码注释不仅可以提升个人的工
- 异常(exceptions)是Python中一种非常重要的类型,它和语法错误不同,是在程序运行期间引发的错误。Python中内置了很多异常,
- 为什么需要优雅关闭什么叫优雅关闭?先说不优雅关闭,就是什么都不管,强制关闭进程,这会导致有些正在处理中的请求被强行中断这样做有什么问题?用户
- 加密接口怎么测试?(1)写个函数或者方法,把要加密的参数使用这个函数过滤一遍,等于就是说把数据丢进去,加密了之后,再通过这个加密好的数据传输
- username1: "(^[a-zA-Z]{1}([a-zA-Z0-9_]){4,14}|(^[\u4E00-\uFA29]{1
- this指针是面向对象程序设计中的一项重要概念,它表示当前运行的对象。在实现对象的方法时,可以使用this指针来获得该对象自身的引用。和其他
- 本文实例讲述了python实现数值积分的Simpson方法。分享给大家供大家参考。具体如下:#coding = utf-8#simpson
- tags: django中对条件查询一些cms项目都会使用到多条件查询,我们后端如何处理请求的条件呢?满足一个条件满足两个条件满足多个条件…
- 不管是用import还是用from mmmm import *的方式导入模块,当程序运行之后,回头在看那个存储着mmmm.py文件的目录中,
- 前缀和后缀HasPrefix判断字符串s是否以prefix开头:strings.HaxPrefix(s string, prefix str
- 前文复习:openCV第一篇openCV第二篇一、Canny边缘检测该边缘检测法步骤如下:使用高斯滤波器,以平滑图像,滤除噪声。计算图像中每
- 本文主要讲述:自定义树形控件<el-tree>需求说明:Element UI 官网提供的树形控件包含基础的、可选择的、自定义节点