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

接口定义

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

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

具体实现

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

package main

import "fmt"

type action interface {
	walk(name string)
}
type sinner struct {
	name string
}

func setName(s *sinner, name string) sinner {
	s.name = name
	return *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 main

import "fmt"

type action interface {
	walk(name string)
	run(name string)
}
type sinner struct {
	name string
}

func setName(s *sinner, name string) sinner {
	s.name = name
	return *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 main

import "fmt"

type action interface {
	walk(name string)
}
type sinner struct {
	name string
}

func setName(s *sinner, name string) sinner {
	s.name = name
	return *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 sinner
		faust   sinner
	)
	setName(&ishmael, "Ishmael")
	setName(&faust, "Faust")
	walking(&ishmael, ishmael.name)
	walking(&faust, faust.name)
}

运行结果如下

Ishmael is walking
Faust is walking 

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

package main

import "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 sinner
		faust   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)
	relationship
	isMyWife(name string)string
}

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

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

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

 

package main

import "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!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值