GoLang之接口interface

article/2025/9/22 22:16:41

文章目录

  • 接口interface
    • 1.接口介绍
    • 2.接口定义
      • 2.1定义要求
      • 2.2接口可以嵌入到其他接口里但必须得匿名
        • 2.2.1接口里可以含一个接口时
        • 2.2.2接口里可以含多个接口时
      • 2.3接口没有数据字段
      • 2.4接口可以嵌入到结构体struct里
      • 2.5空接口可以作为任何类型数据的容器
      • 2.6接口命名习惯以 er 结尾
      • 2.7实现接口的所有方法即可实现接口
        • 2.7.1没有嵌套其他接口时
        • 2.7.1嵌套其他接口时正确实现
        • 2.7.1嵌套其他接口时错误实现
      • 2.8接口是一个或多个方法签名的集合
      • 2.9一个类型可以实现多个接口
        • 2.9.1接口内方法不一样时
        • 2.9.2接口内方法一样时
      • 2.10接口同样支持匿名方法
      • 2.11只有当接口存储的类型和对象都为nil时接口才等于nil
      • 2.12接口类型的变量可使用其实例的方法
      • 2.13接口类型的变量不可以使用其实例的字段
      • 2.14值接收者实现接口
      • 2.15指针接收者实现接口
      • 2.16多个类型实同一接口
      • 2.17结构体中方法+结构体中所嵌套的结构体的方法来实现接口
    • 3.使用接口的原因
    • 4.接口的方法错误定义
    • 5.空接口
      • 5.1空结构体占用16字节
      • 5.2类型断言
        • 5.1定义
        • 5.2v,ok=x.(Y)应用
        • 5.3type switch 语句介绍
        • 5.4结合switch语句

接口interface

1.接口介绍

在Go语言中接口(interface)是一种类型,一种抽象的类型;
interface是一组method的集合,是duck-type programming的一种体现。接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性(数据),只关心行为(方法);
为了保护你的Go语言职业生涯,请牢记接口(interface)是一种类型;
image-20220106085750744

2.接口定义

2.1定义要求

image-20220106091804878

2.2接口可以嵌入到其他接口里但必须得匿名

2.2.1接口里可以含一个接口时

type Phone interface {demo//不会报错
}
type demo interface {}
type Phone interface {aa demo//会编译报错
}
type demo interface {}

2.2.2接口里可以含多个接口时


// Sayer 接口
type Sayer interface {say()
}// Mover 接口
type Mover interface {move()
}// 接口嵌套
type animal interface {SayerMover
}type cat struct {name string
}func (c cat) say() {fmt.Println("喵喵喵")
}func (c cat) move() {fmt.Println("猫会动")
}func main() {var x animalx = cat{name: "花花"}x.move()x.say()
}

2.3接口没有数据字段

接口只有方法声明,没有实现,没有数据字段

2.4接口可以嵌入到结构体struct里

2.5空接口可以作为任何类型数据的容器

2.6接口命名习惯以 er 结尾

2.7实现接口的所有方法即可实现接口

实现接口条件:
接口被实现的条件一:接口的方法与实现接口的类型方法格式一致
接口被实现的条件二:接口中所有方法均被实现
任何类型的方法集中只要拥有该接口’对应的全部方法’签名就表示它 “实现” 了该接口,无须在该类型上显式声明实现了哪个接口,这称为Structural Typing;
所谓对应方法,是指有相同名称、参数列表 (不包括参数名) 以及返回值;
当然该类型还可以有其他方法

2.7.1没有嵌套其他接口时

// Sayer 接口
type Sayer interface {say()
}
type dog struct{}type cat struct{}
// dog实现了Sayer接口
func (d dog) say() {fmt.Println("汪汪汪")
}// cat实现了Sayer接口
func (c cat) say() {fmt.Println("喵喵喵")
}

2.7.1嵌套其他接口时正确实现


type Sayer interface {Listersay()
}
type Lister interface {lis()
}type cat struct{}// dog实现了Sayer接口
func (d cat) say() {fmt.Println("汪汪汪")
}// cat实现了Sayer接口
func (c cat) lis() {fmt.Println("喵喵喵")
}func main() {var x Sayer // 声明一个Sayer类型的变量xa := cat{}  // 实例化一个catx = a       // 会报错,原因缺少say方法x.say()     // 汪汪汪x.lis()
}

2.7.1嵌套其他接口时错误实现


type Sayer interface {Listersay()
}
type Lister interface {lis()
}
type dog struct{}type cat struct{}// dog实现了Sayer接口
func (d dog) say() {fmt.Println("汪汪汪")
}// cat实现了Sayer接口
func (c cat) lis() {fmt.Println("喵喵喵")
}func main() {var x Sayer // 声明一个Sayer类型的变量xa := cat{}  // 实例化一个catb := dog{}  // 实例化一个dogx = a       // 会报错,原因缺少say方法x = b       // 会报错,原因缺少lis方法x.say()     // 汪汪汪}

2.8接口是一个或多个方法签名的集合

2.9一个类型可以实现多个接口

2.9.1接口内方法不一样时


// Sayer 接口
type Sayer interface {say()
}// Mover 接口
type Mover interface {move()
}type dog struct {name string
}// 实现Sayer接口
func (d dog) say() {fmt.Printf("%s会叫汪汪汪\n", d.name)
}// 实现Mover接口
func (d dog) move() {fmt.Printf("%s会动\n", d.name)
}func main() {var x Sayervar y Movervar a = dog{name: "旺财"}x = ay = ax.say()  //输出:旺财会叫汪汪汪y.move() //输出:旺财会动
}

2.9.2接口内方法一样时


// Sayer 接口
type Sayer interface {say()
}// Mover 接口
type Mover interface {say()
}type dog struct {name string
}// 实现Sayer接口
func (d dog) say() {fmt.Printf("%s会叫汪汪汪\n", d.name)
}func main() {var x Sayervar y Movervar a = dog{name: "旺财"}x = ay = ax.say() //输出:旺财会叫汪汪汪y.say()//输出:旺财会叫汪汪汪
}

2.10接口同样支持匿名方法

type Phone interface {func() string  //匿名时候需要加funcsay() string  //不匿名时候不用加func
}

2.11只有当接口存储的类型和对象都为nil时接口才等于nil

2.12接口类型的变量可使用其实例的方法

接口类型的变量可使用其实例的方法 ,但是不可以使用其实例的字段

// Sayer 接口
type Sayer interface {say()
}
type dog struct {a int
}type cat struct{}// dog实现了Sayer接口
func (d dog) say() {fmt.Println("汪汪汪")
}// cat实现了Sayer接口
func (c cat) say() {fmt.Println("喵喵喵")
}func main() {var x Sayer // 声明一个Sayer类型的变量xa := cat{}  // 实例化一个catb := dog{}  // 实例化一个dogx = a       // 可以把cat实例直接赋值给xx.say()     // 喵喵喵x = b       // 可以把dog实例直接赋值给xx.say()     // 汪汪汪}

2.13接口类型的变量不可以使用其实例的字段


// Sayer 接口
type Sayer interface {say()
}
type dog struct {a int
}// dog实现了Sayer接口
func (d dog) say() {fmt.Println("汪汪汪")
}func main() {var x Sayer b := dog{a :4,}x = b       x.say()    fmt.Println(x.a)   //会编译出错
}

2.14值接收者实现接口

从下面的代码中我们可以发现,使用值接收者实现接口之后,不管是dog结构体还是结构体指针dog类型的变量都可以赋值给该接口变量。因为Go语言中有对指针类型变量求值的语法糖,dog指针fugui内部会自动求值fugui

type Mover interface {move()
}type dog struct{}func (d dog) move() {fmt.Println("狗会动")
}func main() {var x Movervar wangcai = dog{} // 旺财是dog类型x = wangcai         // x可以接收dog类型var fugui = &dog{}  // 富贵是*dog类型x = fugui           // x可以接收*dog类型x.move()
}

2.15指针接收者实现接口

此时实现Mover接口的是dog类型,所以不能给x传入dog类型的wangcai,此时x只能存储dog类型的值

type Mover interface {move()
}type dog struct{}func (d *dog) move() {fmt.Println("狗会动")
}func main() {var x Movervar wangcai = dog{} // 旺财是dog类型x = wangcai         // 这一行会会议报错var fugui = &dog{}  // 富贵是*dog类型x = fugui           // x可以接收*dog类型x.move()
}

2.16多个类型实同一接口


// Mover 接口
type Mover interface {move()
}
type dog struct {name string
}type car struct {brand string
}// dog类型实现Mover接口
func (d dog) move() {fmt.Printf("%s会跑\n", d.name)
}// car类型实现Mover接口
func (c car) move() {fmt.Printf("%s速度70迈\n", c.brand)
}
func main() {var x Movervar a = dog{name: "旺财"}var b = car{brand: "保时捷"}x = ax.move() //输出:旺财会跑x = bx.move() //输出:保时捷速度70迈
}

2.17结构体中方法+结构体中所嵌套的结构体的方法来实现接口

接口的方法可以通过在类型中嵌入其他类型或者结构体来实现


// WashingMachine 洗衣机
type WashingMachine interface {wash()dry()
}// 甩干器
type dryer struct{}// 实现WashingMachine接口的dry()方法
func (d dryer) dry() {fmt.Println("甩一甩")
}// 海尔洗衣机
type haier struct {dryer //嵌入甩干器
}// 实现WashingMachine接口的wash()方法
func (h haier) wash() {fmt.Println("洗刷刷")
}
func main() {var x WashingMachinevar a haierx = ax.dry() //输出:甩一甩}

3.使用接口的原因

上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?
像类似的例子在我们编程过程中会经常遇到:
比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?
比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“图形”来处理呢?
比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?
Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么

type Cat struct{}func (c Cat) Say() string { return "喵喵喵" }type Dog struct{}func (d Dog) Say() string { return "汪汪汪" }func main() {c := Cat{}fmt.Println("猫:", c.Say())d := Dog{}fmt.Println("狗:", d.Say())
}

4.接口的方法错误定义

package mainimport ("fmt"
)type Phone interface {call()
}
//会编译报错
func (i Phone) call() {fmt.Println("q23erg")
}
func main() {}

5.空接口

5.1空结构体占用16字节


type demo interface {
}func main() {var a demofmt.Println(unsafe.Sizeof(a)) //输出16var b interface{}fmt.Println(unsafe.Sizeof(b)) //输出16var c complex64fmt.Println(unsafe.Sizeof(c)) //输出8
}

5.2类型断言

5.1定义

在这里插入图片描述

5.2v,ok=x.(Y)应用

func main() {var x interface{}x = "pprof.cn"v, ok := x.(string)if ok {fmt.Println(v)} else {fmt.Println("类型断言失败")}//输出:pprof.cn
}
func main() {var x interface{}x = "pprof.cn"v, ok := x.(bool)if ok {fmt.Println(v)} else {fmt.Println("类型断言失败")}//输出:类型断言失败
}

5.3type switch 语句介绍

image-20220105140922986
image-20220105140939918

5.4结合switch语句


func justifyType(x interface{}) {switch v := x.(type) {case string:fmt.Printf("x is a string,value is %v\n", v)case int:fmt.Printf("x is a int is %v\n", v)case bool:fmt.Printf("x is a bool is %v\n", v)default:fmt.Println("unsupport type!")}
}
func main() {var x interface{}x = "pprof.cn"justifyType(x) //输出:x is a string,value is pprof.cn
}

http://chatgpt.dhexx.cn/article/wvOj1d7f.shtml

相关文章

java中接口(interface)详解

接口(interface) 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。 接口(interface)是抽象方法和常量值的定义的集合。 从本质上讲&…

接口(interface)

(1)接口定义 接口(interface)是一种定义抽象方法的类型,它没有实现,只有方法签名。接口可以被类实现,实现类必须实现接口中的所有方法。接口通常用于定义类之间的契约关系,以及实现…

TS Interface(接口)

接口(Interface) 用来建立某种代码约定,使得其它开发者在调用某个方法或者创建新的类时,必须遵循接口所定义的代码约定 接口的前面加了一个 I 字母规范 在代码设计中,接口是一种规范;接口通常用于来定义某种规范, 类似于你必须遵守的协议,站在程序角度上…

敏捷项目管理实战第一天 敏捷开发SCURM的前世今生

开篇词 敏捷是互联网时代的超级管理术 你好,我是莫敏。自 2006 年开始接触敏捷,到 2010 年参与组织每年一届的敏捷大会,再到 2012 年加入腾讯先后从事项目管理和产品管理工作,可以说从过去到现在,我一直身处敏捷实践的…

机器人算法之敏捷开发

0. 简介 在开发大型的机器人工程时候,我们会发现团体开发以及代码的review的会非常重要。而这些离不开敏捷开发(Scrum)以及Git管理。而最常用敏捷开发流程就是DoD。本文也将介绍和学习这种方式,来辅助各位能够在实验室和工作中团…

何谓敏捷开发

敏捷开发(agile development)是非常流行的软件开发方法。据统计,2018年90%的软件开发采用敏捷开发。 但是,到底什么是敏捷开发,能说清的人却不多。本文尝试用简洁易懂的语言,解释敏捷开发。 一、迭代开发 …

敏捷开发思想

敏捷开发思想 SCRUM 是什么?敏捷开发是什么?以人为核心是什么意思?迭代 是什么意思? SCRUM 与 敏捷开发思想有什么关系?敏捷开发的模式分类(摘抄至互联网):SCRUM 的工作流程(摘抄至互联网) 流程: SCRUM 是…

敏捷开发-Scrum过程模型

Scrum过程模型 Scrum过程: Scrum的三个主要元素:角色(role)、活动(activity)、产出物(artifact) 三个角色: 1. Product Owner(PO) 定义产品需求…

瀑布开发与敏捷开发的区别,以及从瀑布转型敏捷项目管理的5大注意事项

事实证明,瀑布开发管理模式并不适合所有的软件项目,但敏捷项目管理却对大多数项目有效。那么当团队选择转型敏捷的时候有哪些因素必须注意? 敏捷开发最早使用者大多是小型、独立的团队,他们通常致力于小型、独立的项目。正是他们的…

敏捷开发流程简介

最小可行化产品 硅谷创业家 Eric Rise 在其著作 《精益创业》 一书中提出了 “精益创业”(Lean Startup)的理念,其核心思想是,开发产品时先做出一个简单的原型——最小化可行产品,然后通过测试并收集用户的反馈&#…

浅谈敏捷开发中的设计

敏捷开发在当今业界已经大行其道,想要快速交付,采用敏捷开发方法似乎是最好的方式,是否必须要用这就另当别论了。敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发,不过,想要真正做到…

什么是敏捷开发?敏捷开发流程的8个步骤

文章目录 一、什么是敏捷开发?二、敏捷开发模式的分类三、SCRUM 的工作流程四、敏捷开发流程的8个步骤包括:五、敏捷开发模型 一、什么是敏捷开发? 敏捷开发(Agile)是一种以人为核心、迭代、循序渐进的开发方法。 在…

什么是敏捷开发?教你正确理解敏捷开发

敏捷开发是相对于瀑布开发来说,一种轻量级的软件开发方式。敏捷开发是为了快速响应需求变化、通过组建跨职能团队实现持续不断的交付高质量的产品的方法的集合。所有符合敏捷宣言和敏捷开发十二项原则的方法都可以是敏捷开发的一种实践。 在大多数的敏捷开发实践过…

什么是敏捷开发?

什么是敏捷开发? 敏捷开发是一种以人为核心,迭代,循序渐进的开发方式。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。加单的说,敏捷开…

GridView 激发了未处理的事件“PageIndexChanging”

在手动给gridview邦定数据源时,会出现这种情况 运行后直接显示分页的1,只有1显示正常,如果点选其它的,比如2或者4什么其它别的,提示: GridView“XXX”激发了未处理的事件“PageIndexChanging”。 手动分页必须有PageIndexChanging事件,添加PageI…

PageView的设置

1、创建一个PageView控件,自动生成background精灵和mask的view视图和indicator View下面有一个content(Layout类型) ,content可以存放每页内容 页面指示器,可以清晰看当前是多少也 2、监听PageView事件 // 监听事件 o…

ViewPager和PageAdapter,FragmentPageAdapter,FragmentStatePageFragment

【Android】ViewPager深入解析(一) http://www.imooc.com/article/2580 2015-12-07 11:59:28 11830浏览 19评论 话说小伙伴们在使用App的时候有没有注意到很多App的首页都是可以左右滑动的页面呢?很多App还有绚丽的轮播图广告。那么如何实现这…

viewpager.setcurrentitem导致的ANR

参考:Java线程Dump分析工具–jstack dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注) 执行中,Runnable 等待资源,Waiting on condition(重点关注&#x…

对GridView、DetailsView 和 FormView 控件分页属性的PagerSettings类的设置

如果想让分页导航加上图片形式或比如上一页下一页,这种样式,那就要在<GridView>写在这里面</GridView>控件中加上<PagerSettings></PagerSettings>,例如:<PagerSettings Mode="NextPreviousFirstLast" FirstPageText="首页"…