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!

相关内容

热门资讯

原创 中... 联合国的最新表态令人精神一振,这种明确态度其实本就顺理成章。台湾自古属于中国,这是铁一般的事实,中国...
花800元就能买自己的死亡证明... 花800元就能买到 本人的精神诊断报告和死亡证明? 近日,“假证定制”业务 在多个电商和社交平台 死...
智能平台支撑政策落地 实达集团... 11月17日,福建省发展和改革委员会网站发布《福建省数据管理局关于印发〈福建省数据流通交易管理办法(...
祥明智能:制定对外投资管理制度 祥明智能公告称,为规范公司及控股子公司对外投资、资产处置的程序及审批权限,建立有效控制机制保障资金运...
美国9月非农数据受政府关门扰动... 11月21日,中国银河证券发布研报对美国9月非农数据进行点评。研报指出,9月新增就业回到增长区间,失...
原创 高... 近日,随着日本政坛极端言论频频出现,尤其是汉奸石平的发声,再次引发了人们对中日关系未来走势的广泛关注...
日媒曝光:日本曾制定3套“夺岛... 据央视新闻报道,随着日本首相高市早苗涉台挑衅言论持续发酵,日本自卫队在靠近台海的岛屿加强军力部署的情...
舞蹈家黄豆豆获破格提拔,已任副... 今年4月拟破格提拔的舞蹈家黄豆豆,已有新消息。 澎湃新闻注意到,中国舞蹈家协会官网近日更新后显示,黄...
李霄鹏告别青岛海牛:战术调整与... 随着2023赛季的落幕,李霄鹏教练组已正式与青岛海牛球员告别,确认下赛季将不再继续执教。这一决定不仅...