您的位置:首页 > 娱乐 > 明星 > 百度网址导航主页_武汉网站seo德升_网络营销品牌公司_成品网站1688入口网页版怎样

百度网址导航主页_武汉网站seo德升_网络营销品牌公司_成品网站1688入口网页版怎样

2025/3/14 18:13:17 来源:https://blog.csdn.net/theaipower/article/details/146182167  浏览:    关键词:百度网址导航主页_武汉网站seo德升_网络营销品牌公司_成品网站1688入口网页版怎样
百度网址导航主页_武汉网站seo德升_网络营销品牌公司_成品网站1688入口网页版怎样

在这里插入图片描述

本文目录

  • 1.接口型函数
    • 案例
    • 方式1 GetterFunc 类型的函数作为参数
    • 方式2 实现了 Getter 接口的结构体作为参数
    • 价值
  • 2.net/http包中的使用场景

之前写Geecache的时候,遇到了接口型函数,当时没有搞懂,现在重新回过头研究复习Geecache的时候,发现看得懂一些了,刚好能梳理下。

什么是接口型函数?比如下面这个 。

在这里插入图片描述

1.接口型函数

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),紧接着定义了一个函数类型 GetterFuncGetterFunc 参数和返回值与 GetterGet 方法是一致的。

而且 GetterFunc 还定义了 Get 方式,并在 Get 方法中调用自己,这样就实现了接口 Getter。所以 GetterFunc 是一个实现了接口的函数类型,简称为接口型函数

接口型函数只能应用于接口内部只定义了一个方法的情况,例如接口 Getter 内部有且只有一个方法 Get。既然只有一个方法,为什么还要多此一举,封装为一个接口呢?

定义参数的时候,直接用 GetterFunc 这个函数类型不就好了,让用户直接传入一个函数作为参数,不更简单吗?

看案例之前,我们再梳理一下原理。

  • 首先定义了一个接口 Getter ,它要求实现一个 Get 方法
  • 然后定义了一个函数类型 GetterFunc ,其签名与 Get 方法相同
  • 最关键的是,为 GetterFunc 类型实现了 Get 方法,该方法内部直接调用函数本身。

这样,任何符合 GetterFunc 签名的函数都可以被转换为 Getter 接口类型,从而进行使用。


案例

假设 GetFromSource 的作用是从某数据源获取结果,接口类型 Getter 是其中一个参数,代表某数据源:

func GetFromSource(getter Getter, key string) []byte {buf, err := getter.Get(key)if err == nil {return buf}return nil
}

方式1 GetterFunc 类型的函数作为参数

我们可以用多种方式来实现这个这个函数。

比如方式一:GetterFunc类型的函数作为参数。下面就是用一个匿名函数(GetterFunc类型)来作为参数。使用 GetterFunc() 将这个匿名函数转换为 GetterFunc 类型,这样它就实现了 Getter 接口

GetFromSource(GetterFunc(func(key string) ([]byte, error) {return []byte(key), nil
}), "hello")

也可以用普通的函数。

func test(key string) ([]byte, error) {return []byte(key), nil
}func main() {GetFromSource(GetterFunc(test), "hello")
}

test函数强制转换为GetterFunc,而GetterFunc实现了接口Getter,是一个合法的参数。

本质上,上面两种方式是类型转换,在go中我们定义了一个新类型,可以用这个新的类型名作为函数来进行类型转换,比如下面 字符串类型转换。

type String string// 将普通字符串转换为 String 类型
str := String("1234")

我们把“函数”也看做是一种类型,(字符串、整数这些都是类型),那么也可以实现 函数 类型转换,比如。

type GetterFunc func(key string) ([]byte, error)// 将匿名函数转换为 GetterFunc 类型
getter := GetterFunc(func(key string) ([]byte, error) {return []byte(key), nil
})

这两种情况本质上是相同的:都是将一个值转换为自定义类型。区别在于一个转换的是函数,另一个转换的是字符串。

// 使用普通函数作为数据源
func dbGetter(key string) ([]byte, error) {// 从数据库获取数据return []byte("value from db"), nil
}// 将函数转换为Getter接口
var getter Getter = GetterFunc(dbGetter)// 现在可以在任何需要Getter接口的地方使用
data, err := getter.Get("some_key")

方式2 实现了 Getter 接口的结构体作为参数

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,也是一个合法参数。这种方式适用于逻辑较为复杂的场景,如果对数据库的操作需要很多信息,地址、用户名、密码,还有很多中间状态需要保持,比如超时、重连、加锁等等。这种情况下,更适合封装为一个结构体作为参数。


价值

综上,这样,既能够将普通的函数类型(需类型转换)作为参数,也可以将结构体作为参数,使用更为灵活,可读性在使用函数(方式1)的时候某种程度上会更好,这就是接口型函数的价值。

2.net/http包中的使用场景

上面的特性,在标准库中用得很多,net/httpHandlerHandlerFunc 就是一个典型。

看看Handler定义。

type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}

我们可以 http.Handle 来映射请求路径和处理函数,Handle 的定义如下所示。

func Handle(pattern string, handler Handler)

这里需要的第二参数是接口类型Handler

func home(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK)_, _ = w.Write([]byte("hello, index page"))
}func main() {http.Handle("/home", HandlerFunc(home))_ = http.ListenAndServe("localhost:8000", nil)
}

通常还有另一个函数,http.HandleFuncHandleFunc 的定义如下:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

第二个参数是一个普通的函数类型,那可以直接将 home 传递给 HandleFunc,实现代码如下。

func main() {http.HandleFunc("/home", home)_ = http.ListenAndServe("localhost:8000", nil)
}

看看 HandleFunc 的内部实现逻辑。

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {if handler == nil {panic("http: nil handler")}mux.Handle(pattern, HandlerFunc(handler))
}

可以看到,mux.Handle(pattern, HandlerFunc(handler))

两种写法是完全等价的,内部将第二种写法转换为了第一种写法。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com