转载自:https://geektutu.com/post/7days-golang-q1.html
在 动手写分布式缓存 - GeeCache第二天 单机并发缓存 这篇文章中,有一个接口型函数的实现: 1 2 3 4 5 6 7 8 9 10 11 12 // A Getter loads data for a key. type Getter interface { Get(key string) ([]byte, error) } // A GetterFunc implements Getter with a function. type GetterFunc func(key string) ([]byte, error) // Get implements Getter interface function func (f GetterFunc) Get(key string) ([]byte, error) { return f(key) } 这里呢,定义了一个接口 Getter,只包含一个方法 Get(key string) ([]byte, error),紧接着定义了一个函数类型 GetterFunc,GetterFunc 参数和返回值与 Getter 中 Get 方法是一致的。而且 GetterFunc 还定义了 Get 方式,并在 Get 方法中调用自己,这样就实现了接口 Getter。所以 GetterFunc 是一个实现了接口的函数类型,简称为接口型函数。 这个接口型函数的实现就引起了好几个童鞋的关注。接口型函数只能应用于接口内部只定义了一个方法的情况,例如接口 Getter 内部有且只有一个方法 Get。既然只有一个方法,为什么还要多此一举,封装为一个接口呢?定义参数的时候,直接用 GetterFunc 这个函数类型不就好了,让用户直接传入一个函数作为参数,不更简单吗? 所以呢,接口型函数的价值什么? 价值 我们想象这么一个使用场景,GetFromSource 的作用是从某数据源获取结果,接口类型 Getter 是其中一个参数,代表某数据源: 1 2 3 4 5 6 7 func GetFromSource(getter Getter, key string) []byte { buf, err := getter.Get(key) if err == nil { return buf } return nil } 我们可以有多种方式调用该函数: 方式一:GetterFunc 类型的函数作为参数 1 2 3 GetFromSource(GetterFunc(func(key string) ([]byte, error) { return []byte(key), nil }), "hello") 支持匿名函数,也支持普通的函数: 1 2 3 4 5 6 7 func test(key string) ([]byte, error) { return []byte(key), nil } func main() { GetFromSource(GetterFunc(test), "hello") } 将 test 强制类型转换为 GetterFunc,GetterFunc 实现了接口 Getter,是一个合法参数。这种方式适用于逻辑较为简单的场景。 方式二:实现了 Getter 接口的结构体作为参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 type DB struct{ url string} func (db *DB) Query(sql string, args ...string) string { // ... return "hello" } func (db *DB) Get(key string) ([]byte, error) { // ... v := db.Query("SELECT NAME FROM TABLE WHEN NAME= ?", key) return []byte(v), nil } func main() { GetFromSource(new(DB), "hello") } DB 实现了接口 Getter,也是一个合法参数。这种方式适用于逻辑较为复杂的场景,如果对数据库的操作需要很多信息,地址、用户名、密码,还有很多中间状态需要保持,比如超时、重连、加锁等等。这种情况下,更适合封装为一个结构体作为参数。 这样,既能够将普通的函数类型(需类型转换)作为参数,也可以将结构体作为参数,使用更为灵活,可读性也更好,这就是接口型函数的价值。 使用场景 这个特性在 groupcache 等大量的 Go 语言开源项目中被广泛使用,标准库中用得也不少,net/http 的 Handler 和 HandlerFunc 就是一个典型。 我们先看一下 Handler 的定义: 1 2 3 4 5 6 7 8 type Handler interface { ServeHTTP(ResponseWriter, *Request) } type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }