【Go】Go 语言中的接口


一、接口

Go 语言提供了另外一种数据类型:接口(interface),它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

接口是一组方法签名的集合,然后我们可以定义一个结构体实现该接口所有方法。因此,接口就是定义了对象的行为。

例如,结构体Dog可以walk和bark, 如果一个接口声明了walk和bark的方法签名,而Dog实现了walk和bark方法,那么Dog就实现了该接口。

接口的主要工作是仅提供由方法名称,输入参数和返回类型组成的方法签名集合。 由类型(例如struct结构体)来声明方法并实现它们。
(如果不在类型上实现接口中的方法,那么接口仍然是一个概念)

如果一个类型实现了在接口中定义的所有声明方法,则称该类型实现了该接口。

我说:
接口只是一个方法的集合(只是一个概念,只是一个概念上的集合)。
接口中声明的方法的具体实现是基于一个类型的(struct结构体)。
如果,实现了定义在某个结构体类型上的多个方法,而所有这些方法恰好组成了一个接口;那么就说该结构体类型实现了该接口。

我再说:
接口是基于类型(结构体)实现的。
可以基于很多不同的类型实现这个接口。(同样,一个类型也可以实现多个接口)
所以声明一个接口之后,要用某个特定的结构体类型来实例化这个接口。(前提:这个特定的结构体类型已经实现了该接口)
然后你就可以用这个接口调用该结构体类型上的所有方法啦。


二、定义接口

/* 定义接口 */
type interface_name interface {
    
    
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
    
    
   /* variables */
}

/* 在结构体上实现接口方法 */
func (struct_variable_name struct_name) method_name1() [return_type] {
    
    
   /* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
    
    
   /* 方法实现*/
}

说明:

  1. 接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。

  2. 方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

  3. 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。


三、实例

package main

import (
	"fmt"
)


//定义接口 Phone
//接口 Phone 里有一个方法 call()
type Phone interface {
    
    
	call()
}


//定义结构体
type NokiaPhone struct {
    
    
}


//在结构体 NokiaPhone 上实现接口方法
func (nokiaPhone NokiaPhone) call() {
    
    
	fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
    
    
}

//在结构体 IPhone 上实现接口方法
func (iPhone IPhone) call() {
    
    
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
    
    
	//声明了一个新的接口phone 
	var phone Phone

	//用结构体 NokiaPhone 来实例化接口phone 
	//使用 new 函数来为自定义类型分配空间
	phone = new(NokiaPhone)
	//用接口phone调用该结构体上的方法
	phone.call()

	//用结构体 IPhone 来实例化接口phone
	phone = new(IPhone)
	phone.call()

}

输出结果:

I am Nokia, I can call you!
I am iPhone, I can call you!

四、Go语言中文文档中定义的接口

  1. 接口是什么

接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。

在Go语言中接口(interface)是一种类型,一种抽象的类型。

  1. 实现接口的条件

一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。

接口的实现就是这么简单,只要实现了接口中的所有方法,就实现了这个接口。

  1. 接口有什么用

先看一个不用接口的例子:

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())
}

上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?

像类似的例子在我们编程过程中会经常遇到:
比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?
比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“图形”来处理呢?
比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?

Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么。

下面通过一个实例体会一下实现了接口有什么用:

package main

import (
	"fmt"
)

type Sayer interface {
    
    
	Say()
}

//声明了一个 Cat 结构体
type Cat struct{
    
    }

//在 Cat 结构体上实现方法 Say()
func (c Cat) Say() {
    
     fmt.Println("喵喵喵") }

//声明了一个 Dog 结构体
type Dog struct{
    
    }

//在 Dog 结构体上实现方法 Say()
func (d Dog) Say() {
    
     fmt.Println("汪汪汪") }

func main() {
    
    
	var x Sayer // 声明一个Sayer类型的变量x
	a := Cat{
    
    }  // 实例化一个cat
	b := Dog{
    
    }  // 实例化一个dog
	x = a       // 可以把cat实例直接赋值给x
	x.Say()     // 喵喵喵
	x = b       // 可以把dog实例直接赋值给x
	x.Say()     // 汪汪汪
}

输出结果:

喵喵喵
汪汪汪

接口类型变量能够存储所有实现了该接口的实例。

例如上面的示例中,Sayer类型的变量能够存储Dog 和Cat 类型的变量。

通过对不同的Sayer调用方法Say,就能让他们说自己的话。


参考链接

  1. Go 语言接口
  2. go语言中的接口
  3. 接口 · Go语言中文文档

猜你喜欢

转载自blog.csdn.net/weixin_44211968/article/details/121395529