这个系列文章我会总结一下我在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使用。
本文转载自: 掘金