GO语言--接口(interface)的定义及使用
创始人
2025-05-29 05:00:42
0

接口定义

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

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

具体实现

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

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!

相关内容

热门资讯

C++类和对象(上) 引入:C语言是面向过程的,关注的是过程,就是分析出解决问题...
gdb调试工具和makemak... gdb调试工具和make/makefile工具 文章目录gdb调试工具和make/makefile工...
【Java】Vert.x使用M... 当初为了学习Docker和自动化运维方面的知识,在家里的机器中也部署了一整套运维工具。...
final与static的区别 都可以修饰类、方法、成员变量。都不能用于修饰构造方法。static 可以修饰类的代码块,...
软件架构Class-3-not... Note 文章目录NoteB/S结构httpservlet & servlet实现httpservl...
【python】pip安装与使... python pip安装与使用一、pip的安装与使用pip介绍pypi仓库pip介绍pip的基础使用...
港报:香港跃升为国际调解枢纽 参考消息网5月31日报道香港《信报》5月29日发表题为《香港跃升国际调解枢纽》的文章,作者是香港特区...
相乘-蓝桥杯真题-python... 题目描述  解题思路 又是一道数据量大的,如果你从正面按照他题给那个条件遍历一个数&...
欧拉筛- 计数质数 给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。 示例 1: 输入:n = 10 输...