#go
#设计模式
Go 接口型函数
接口型函数是实现了某个接口的函数。适用于只有一个方法的接口。
// 定义一个接口,只包含一种方法
type animal interface {
run(string)
}
// 定义一个函数类型 这个方法的参数和接口里的方法一致
type animalFunc func(string)
// 定义 animalFunc 的方法 实现animal接口
// 执行 接收器本身
func (afunc animalFunc) run(text string){
afunc(string)
}
当看到上面这种“三件套”式的写法就意味着接口型函数要出现了。
- 定义了一个接口。
- 定义了一个函数类型。
- 函数类型定义了方法实现接口,并在内部执行函数类型本身。
func sayHello(text string) {
// do something
}
// 接口型函数
animalFunc(sayHello)
现在定义了一个函数sayHello,并进行类型animalFunc的转换,实现了接口,就形成了接口型函数。
那这样封装的好处是什么?
示例
先定义一个接口
type Animal interface {
run()
}
我们定义一个函数,其中需要接口作为参数
func makeAnimalRun(something Animal){
something.run()
}
现在我们要在main函数里调用这个函数,有哪些方式?
第一种就是定一个类型去实现接口
type Rabbit struct{}
func (r Rabbit) run(){
fmt.Println("rabbit is running")
}
type Dog struct{}
func (d Dog) run(){
fmt.Println("dog is running")
}
func main(){
rabbit := Rabbit{}
makeAnimalRun(rabbit)
//=> "rabbit is running"
dog := Dog{}
makeAnimalRun(dog)
//=> "dog is running"
}
第二种情况,我觉得每次调用makeAnimalRun都要新定一个动物名字的结构体,很麻烦。现在我不想搞结构体,或者新定义个类型。
于是乎我们可以用接口型函数,往makeAnimalRun函数里传函数作为参数
type Animal interface {
run()
}
type AnimalFunc func()
func (r AnimalFunc) run() {
r()
}
以上是实现接口型函数的基本操作 下面我们往makeAnimalRun中传入函数
func peopleRun(){
fmt.Println("somebody is running")
}
func main(){
makeAnimalRun(AnimalFunc(peopleRun))
//=> somebody is running
}
接口型函数的作用在此就得以实现,AnimalFunc(peopleRun)的作用是把peopleRun这个函数强制转换为AnimalFunc函数类型,makeAnimalRun需要执行接口的run方法,而AnimalFunc函数类型的run方法就是执行接收器本身。
我们可以进一步优化,再外套一层函数来隐藏这种强制转换。
func makeAnimalRunFunc(f func()) {
makeAnimalRun(AnimalFunc(f))
}
至此我们就可以通过传递两种参数来作为接口参数实现功能
func main() {
// 传入结构体
rabbit := Rabbit{}
makeAnimalRun(rabbit) //=> "rabbit is running"
// 传入函数,函数被强制转换实现了接口
makeAnimalRun(AnimalFunc(peopleRun)) //=> "somebody is running"
// 封装了强制转换,直接传函数
makeAnimalRunFunc(peopleRun) //=> "somebody is running"
}
总结下来,接口型函数的意义,就是使有些需要接口作为参数的函数上,传入的参数可以是实现了该接口的类型,也可以是函数,这个函数是被满足接口的函数类型强制转换了。
参考
https://geektutu.com/post/7days-golang-q1.html
https://blog.csdn.net/michael__li/article/details/53941399