当前位置: 首页 > news >正文

GO语言--接口(interface)的定义及使用

接口定义

接口也是一种数据类型,它代表一组方法的集合。

接口是非侵入式的。即接口设计者无需知道接口被哪些类型实现,而接口使用者只需知道实现怎样的接口,并且无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口,或者接口该由谁来实现。

具体实现

直接来看例子。首先接口方法的功能必须通过结构体来实现。例子如下

package mainimport "fmt"type action interface {walk(name string)
}
type sinner struct {name string
}func setName(s *sinner, name string) sinner {s.name = namereturn *s
}
func (s *sinner) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func walking(a action, name string) {a.walk(name)
}
func main() {var (tmp sinner)setName(&tmp, "Ishmael")walking(&tmp, tmp.name)
}

运行结果为

 Ishmael is walking

可以看到我们并没有直接调用walk()方法,而是通过walking()函数去调用walk()函数。

在主函数中,将sinner结构体与action接口绑定的是这一步。我们将sinner结构体实例化(给结构里的name赋值"Ishmael",然后生成实例化变量tmp。再将tmp的地址传入到walking()函数中。此时,由于walking()函数中变量a的类型为action,而我们传入的变量tmp类型为(*sinner),结构体sinner便与接口action绑定在了一起。

	walking(&tmp, tmp.name)

“鸭子类型”(Duck Typing)。

只要走起来像鸭子,或者游泳姿势像鸭子,或者叫声像鸭子,那么它就是一只鸭子。用官方术语来解释:鸭子类型只关注事物的外部行为而非内部结构。

我们将接口与结构体的绑定过程通过函数实现。只要我们传入结构体的实例化变量,函数就能自动执行接口方法。这样就不需要每次当我们要去调用一个接口时,都要去新建一个接口变量绑定对应的结构体实例化变量,再通过其调用接口。

不过需要注意的是,如果接口包含多个方法,那么结构体必须要为每个方法实现具体功能,不然会出现报错。我们试着添加向action接口中添加一个run()方法。

package mainimport "fmt"type action interface {walk(name string)run(name string)
}
type sinner struct {name string
}func setName(s *sinner, name string) sinner {s.name = namereturn *s
}
func (s *sinner) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func walking(a action, name string) {a.walk(name)fmt.Printf("%T", a)
}
func main() {var (tmp sinner)setName(&tmp, "Ishmael")walking(&tmp, tmp.name)
}

运行结果为,可以看到会提示异常。

 # command-line-arguments
.\cpt.1.go:29:10: cannot use &tmp (value of type *sinner) as action value in argument to walking: *sinner does not implement action (missing method run)

编译完成,并显示退出代码 1
 

多态 

 同一结构体的不同实例化可以使用同一个接口,例子如下

package mainimport "fmt"type action interface {walk(name string)
}
type sinner struct {name string
}func setName(s *sinner, name string) sinner {s.name = namereturn *s
}
func (s *sinner) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func walking(a action, name string) {a.walk(name)
}
func main() {var (ishmael sinnerfaust   sinner)setName(&ishmael, "Ishmael")setName(&faust, "Faust")walking(&ishmael, ishmael.name)walking(&faust, faust.name)
}

运行结果如下

Ishmael is walking
Faust is walking 

不同结构体的实例化也能调用同一接口。我们修改一下上面的代码,将setName方法也整合进接口,再新建一个结构enemy。例子如下

package mainimport "fmt"type action interface {walk(name string)setName(name string)
}
type sinner struct {name string
}
type enemy struct {name string
}func (s *sinner) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func (s *sinner) setName(name string) {s.name = name
}
func (s *enemy) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func (s *enemy) setName(name string) {s.name = name
}func setname(a action, name string) {a.setName(name)
}
func walking(a action, name string) {a.walk(name)
}
func main() {var (ishmael sinnerfaust   enemy)setname(&ishmael, "Ishmael")setname(&faust, "Faust")walking(&ishmael, ishmael.name)walking(&faust, faust.name)
}

运行结果如下

Ishmael is walking
Faust is walking 

接口嵌套 

接口可以嵌套另一个接口,通过接口嵌套,接口之间能形成简单的基础关系。但接口之间不具备方法重写功能,即多个接口嵌套组成一个新的接口,每个接口的方法都是唯一的。即不能出现下面这种情况--不同接口中定义了相同的方法名,但两个方法的返回值不一样。


type relationship interface {isMyWife(name string)int
}
type action interface {walk(name string)setName(name string)relationshipisMyWife(name string)string
}

把返回类型去掉或者改为同一种就行了,程序才能把两个不同接口里但定义相同的方法,当作一个方法去执行。

type relationship interface {isMyWife(name string) 
}
type action interface {walk(name string)setName(name string)relationshipisMyWife(name string) 
}

 综上,我们优化下程序可以得到一个嵌套了其他接口的接口,并通过函数的方式对其调用。

 

package mainimport "fmt"type relationship interface {relationship_isMyWife(name string)
}
type action interface {walk(name string)setName(name string)relationship
}
type sinner struct {name string
}func (s *sinner) walk(name string) {fmt.Printf("%v is walking\n", s.name)
}
func (s *sinner) setName(name string) {s.name = name
}
func (s *sinner) relationship_isMyWife(name string) {fmt.Printf("%v is my Wife!\n", s.name)
}
func getInterface(a action, name string) {a.setName(name)a.walk(name)a.relationship_isMyWife(name)
}
func main() {var (ishmael sinner)getInterface(&ishmael, "Ishmael")
}

运行结果如下

Ishmael is walking
Ishmael is my Wife!

http://www.lryc.cn/news/40219.html

相关文章:

  • 【Python语言基础】——Python MongoDB 查询
  • 第十四届蓝桥杯模拟赛【第三期】Python
  • windows 下docker 安装clickhouse
  • 【华为OD机试真题 JAVA】TLV编码问题
  • 深度学习 Day26——使用Pytorch实现猴痘病识别
  • redis简单介绍
  • Understanding services:理解服务(Service)
  • 【链表OJ题(五)】合并两个有序链表
  • C++ Primer第五版_第三章习题答案(1~10)
  • 小样本学习
  • python打包成apk界面设计,python打包成安装文件
  • pytorch转onnx踩坑日记
  • 极智AI | GPT4来了,ChatGPT又该升级了
  • 智能优化算法之灰狼优化算法(GWO)的实现(Python附源码)
  • leetCode热题10-15 解题代码,思路
  • 同步辐射GISAXS和GIWAXS的原理及应用领域
  • OpManager 进行网络性能管理
  • 面试被问到向上转型和向下转型时,怎么回答?
  • 加密月解密:概述,基础篇
  • DC-DC升压模块隔离高压稳压电源直流变换器12v24v48v转600V1000V1100V1500V2000V3000V
  • pandas数据分析(三)
  • cpu performance profiling
  • vue2启动项目npm run dev报错 Error: Cannot find module ‘babel-preset-es2015‘ 修改以及问题原因
  • *9 set up 注意点
  • linux目录——文件管理
  • 使用new bing简易教程
  • idea插件分享 显著提高开发效率
  • 文心一言发布我怎么看?
  • 100. 增减序列
  • 操作系统之进程的初步认识(1)