// 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)
}

接口型函数(Interface Function)(最典型的应用就是 Go 标准库 net/http 中的 http.HandlerFunc)。

我们可以把这段代码拆开,看看到底是怎么让“一个函数”去“实现接口”的:


1. 关键拆解:把函数定义成了一个“类型”

首先看这一行:

type GetterFunc func(key string) ([]byte, error)
 

Go 允许用 type 定义任何自定义类型。这里不是在定义普通函数,而是在**定义一个新的“自定义函数类型” GetterFunc**。

  • 只要一个函数的参数是 (key string)、返回值是 ([]byte, error),它的签名就和 GetterFunc 完全一致。

2. 体现实现接口的地方:给函数类型绑定方法

真正的魔术在这一步:

func (f GetterFunc) Get(key string) ([]byte, error) {
    return f(key)
}
 

按照 Go 的语法规则:

  1. 接口要求:Getter 接口要求有一个 Get(key string) ([]byte, error) 方法。
  2. 方法绑定:func (f GetterFunc) Get(...) 给自定义类型 GetterFunc 绑定了一个叫 Get 的方法。
  3. 满足接口:因为 GetterFunc 拥有了 Get 方法,且方法签名与 Getter 接口定义的完全一致,所以 GetterFunc 这个类型隐式实现了 Getter 接口!

在 Get 方法内部,f(key) 就是直接调用 f 函数自己。


3. 为什么不直接用结构体实现?这样写有什么妙用?

如果不这么写,传统方式必须用结构体来实现接口:

传统方式(基于结构体):

必须先定义结构体,再写方法,调用时必须实例化结构体:

// 1. 定义结构体
type DBGetter struct{}
 
// 2. 实现接口
func (db DBGetter) Get(key string) ([]byte, error) {
    return []byte("from db"), nil
}
 
// 3. 使用:必须传结构体实例
func GetFromSource(g Getter, key string) {
    data, _ := g.Get(key)
    fmt.Println(string(data))
}
 
GetFromSource(DBGetter{}, "some_key")
 

接口型函数方式(极简):

有了 GetterFunc 之后,你可以直接把一个匿名函数/闭包当成接口传进去,无需定义任何结构体!

// 只需要用 GetterFunc(...) 做一次显式类型转换:
GetFromSource(GetterFunc(func(key string) ([]byte, error) {
    return []byte("from memory"), nil
}), "some_key")
 

4. 总结

  1. 谁实现了接口? → 是自定义函数类型 GetterFunc,而不是某个 struct。
  2. 怎么体现的? → GetterFunc 绑定了符合 Getter 接口要求的 Get 方法。
  3. 核心价值:让调用方既可以传结构体对象,又可以方便地直接传一个匿名函数(只需用 GetterFunc() 强转一下),极大地提升了 API 的灵活性。