Go 编程 | 连载 23 - 函数实现接口

1,669 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情

Go 编程 | 连载 15 - Go 语言的函数已经讲述了函数的声明以及一等公民特性既把函数赋值给变量或者把函数作为另一个函数的参数。

一、函数实现接口

Go 语言中除了结构体能够实现接口外,函数作为一等公民也可以实现接口。那么结构体实现接口和函数实现接口有什么区别?

结构体实现接口

定义一个接口 Fighter 以及一个结构体 Hero,Hero 实现 Fighter 接口的 Fight 方法时,方法的接收者为结构体指针。

package main

import "fmt"

func main(){

   // 声明接口变量
   var fighter Fighter
   // 函数接收者是一个指针
   hero := Hero{"Peter"}
   heroPtr:= &hero
   
   // Hero 实现 Fighter 接口时函数接收者为结构体指针类型,所有只能将
   // 结构体指针赋值给 fighter 接口变量
   fighter = heroPtr

   fighter.Fight("Suit")

}

type Fighter interface {
   Fight(interface{})
}

type Hero struct {
   Name string
}

// 结构体实现接口
func (h *Hero) Fight(interface{}) {
   fmt.Println(h.Name + " is Fighting!")
}

执行上述代码,输出结果如下:

Peter is Fighting!

函数实现接口

函数的声明不能直接实现接口,需要将函数定义为类型后,使用类型实现结构体。当类型方法被调用时,还需要调用函数本体。

package main

import "fmt"

func main(){

   // 声明接口变量
   var fighter Fighter

   // 实例化一个函数类型对象
   funcFighterInstance := FuncFighter(func(v interface{}) {
      fmt.Println(v, "is Fighting")
   })
   
   // 赋值给接口变量
   fighter = funcFighterInstance

   fighter.Fight("Peter")

}

type Fighter interface {
   Fight(interface{})
}

// 定义一个函数类型
type FuncFighter func(interface{})

// 实现 Fighter 接口的 Fight 方法
func ( funcFighter FuncFighter) Fight(i interface{}) {
   // 调用函数本体,在实例化函数对象时实现函数具体功能,或者直接再次实现函数具体功能,但是实例化函数时定义的函数实现功能会被覆盖。
   // 建议直接在这里调用函数本体,在实例化对象时再实现函数的具体功能。
   funcFighter(i)
}

执行上述代码,输出结果如下:

Peter is Fighting

当类型方法被调用时可以直接实现函数的内容不用调用函数本体,如果调用函数本体,那就需要在实例化函数类型对象时实现函数的具体内容。

函数与结构体实现的区别就在于结构体可以直接实现接口,而函数实现接口则需要使用 type 关键字定义一个函数类型,在通过该函数类型实现接口,并将该函数类型的实例化对象赋值给接口变量,这样就可以通过接口变量来调用函数类型实现的接口功能。