Go之接口型函數(shù)用法
在net/http包中,有一個接口型函數(shù)的實現(xiàn):
type Handler interface {
?? ?ServeHTTP(ResponseWriter, *Request)
}
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
?? ?f(w, r)
}為什么在多路復(fù)用器中不能直接根據(jù)路由取到視圖函數(shù)HandlerFunc然后加括號執(zhí)行呢?
反而還要多此一舉實現(xiàn)Handler接口,然后將函數(shù)包裝后HandlerFunc(f).ServeHTTP(w,r)調(diào)用呢。
價值
既能夠?qū)⑵胀ǖ暮瘮?shù)類型(需類型轉(zhuǎn)換)作為參數(shù),也可以將結(jié)構(gòu)體作為參數(shù),使用更為靈活,可讀性也更好,這就是接口型函數(shù)的價值。
實例1(net/http)
可以 http.Handle 來映射請求路徑和處理函數(shù),Handle 的定義如下:
func Handle(pattern string, handler Handler)
第二個參數(shù)是即接口類型 Handler,
func home(w http.ResponseWriter, r *http.Request) {
?? ?w.WriteHeader(http.StatusOK)
?? ?_, _ = w.Write([]byte("hello, index page"))
}
func main() {
?? ?http.Handle("/home", http.HandlerFunc(home))
?? ?// http.HandlerFunc(home)->HandlerFunc->默認(rèn)的多路復(fù)用器會調(diào)用它的ServeHTTP()方法
?? ?_ = http.ListenAndServe("localhost:8000", nil)
}另外一個函數(shù) http.HandleFunc,HandleFunc 的定義如下:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
第二個參數(shù)是一個普通的函數(shù)類型,
func main() {
?? ?http.HandleFunc("/home", home)
?? ?_ = http.ListenAndServe("localhost:8000", nil)
}兩種寫法是完全等價的,HandleFunc內(nèi)部將第二種寫法轉(zhuǎn)換為了第一種寫法。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
?? ?if handler == nil {
?? ??? ?panic("http: nil handler")
?? ?}
?? ?mux.Handle(pattern, HandlerFunc(handler))
}http.ListenAndServe 的第二個參數(shù)也是接口類型 Handler,使用了標(biāo)準(zhǔn)庫 net/http 內(nèi)置的路由,因此傳入的值是 nil。
如果這個地方傳入的是一個實現(xiàn)了 Handler 接口的結(jié)構(gòu)體,就可以完全托管所有的 HTTP 請求,后續(xù)怎么路由,怎么處理,請求前后增加什么功能,都可以自定義了。慢慢地,就變成了一個功能豐富的 Web 框架了。
實例2(tutu)
// 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)
}假設(shè)有一個方法:
func GetData(getter Getter, key string) []byte {
?? ?buf, err := getter.Get(key)
?? ?if err == nil {
?? ??? ?return buf
?? ?}
?? ?return nil
}如何給該方法傳參呢?
方式一:GetterFunc 類型的函數(shù)作為參數(shù)(匿名函數(shù))
GetData(GetterFunc(func(key string) ([]byte, error) {
?? ?return []byte(key), nil
}), "hello")方式二:普通函數(shù)
func test(key string) ([]byte, error) {
?? ?return []byte(key), nil
}
func main() {
? ? GetData(GetterFunc(test), "hello")
}將 test 強制類型轉(zhuǎn)換為 GetterFunc,GetterFunc 實現(xiàn)了接口 Getter,是一個合法參數(shù)。這種方式適用于邏輯較為簡單的場景。
方式三:實現(xiàn)了 Getter 接口的結(jié)構(gòu)體作為參數(shù)
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() {
?? ?GetData(new(DB), "hello")
}DB 實現(xiàn)了接口 Getter,也是一個合法參數(shù)。這種方式適用于邏輯較為復(fù)雜的場景,如果對數(shù)據(jù)庫的操作需要很多信息,地址、用戶名、密碼,還有很多中間狀態(tài)需要保持,比如超時、重連、加鎖等等。這種情況下,更適合封裝為一個結(jié)構(gòu)體作為參數(shù)。
這樣,既能夠?qū)⑵胀ǖ暮瘮?shù)類型(需類型轉(zhuǎn)換)作為參數(shù),也可以將結(jié)構(gòu)體作為參數(shù),使用更為靈活,可讀性也更好,這就是接口型函數(shù)的價值。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Go語言普通指針unsafe.Pointer?uintpt之間的關(guān)系及指針運算
這篇文章主要為大家介紹了Go語言普通指針unsafe.Pointer?uintpt之間的關(guān)系及指針運算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作
這篇文章主要介紹了Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Go 數(shù)據(jù)庫查詢與結(jié)構(gòu)體映射的示例詳解
本文主要介紹了如何使用Go語言進行數(shù)據(jù)庫查詢并將查詢結(jié)果映射到結(jié)構(gòu)體中,文章詳細(xì)講解了結(jié)構(gòu)體字段導(dǎo)出和db標(biāo)簽的使用方法,并通過示例代碼展示了如何正確地進行數(shù)據(jù)庫查詢和結(jié)果映射2024-11-11

