这个系列文章我会总结一下我在Golang
中经常遇到的一些代码设计
这篇我们看看接口的函数实现,对于像我这样从其他语言转过来的开发者,函数类型以及函数类型方法还是需要理解清楚的。工作中对接口的实现也大多是通过自定义结构体作为类型,然后再为它实现接口,比如:
1 | golang复制代码// alertmanager/notify/notify.go:220 |
这是一种很常见也很好理解的设计,约定接口Stage
然后自定义类型RoutingStage
来实现接口,这样RoutingStage
就可以被所有使用Stage
的位置使用了,但我们看看下面这段:
1 | golang复制代码// alertmanager/notify/notify.go:234 |
这里对比类和实例的概念,把StageFunc
这样定义函数签名的称为函数类型,这个函数类型对应的函数称为函数值,这段代码中定义了一个函数类型 StageFunc
,还为这个函数类型定义了Exec
方法,这样的话这个函数类型是满足Stage
接口的,在Exec
函数中用这个函数值调用Exec
方法时接收的参数调用了这个函数值自己。
举个例子,如果一个函数aFunc
满足func(ctx context.Context, l log.Logger, alerts ...*types.Alert) (context context.Context, []*types.Alert, error)
这样的签名,但这时它还不是StageFunc
类型的函数,可以使用bFunc:=StageFunc(aFunc)
把这个函数值转为StageFunc
类型的函数值,这时候既可以直接调用bFunc()
,还可以bFunc.Exec()
调用。
这是Golang
中一种不是特别常见的设计,当然这种设计的重点也不是对一个函数两种调用方式,而是如何使用函数来实现接口。在net/http
的源码中的HandlerFunc
也是这种设计方式:
1 | golang复制代码// net/http/server.go:2065 |
这里的HandlerFunc
类似一个转换器,把用户自定义的函数转为特定的HandlerFunc
类型,然后通过调用这个类型的方法来调用这个函数,这样相当于开放一个函数签名给用户,用户定义任意满足函数签名的函数就可以被Server
使用。
本文转载自: 掘金