日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Go之接口型函數用法_Golang

作者:Generalzy ? 更新時間: 2023-04-23 編程語言

在net/http包中,有一個接口型函數的實現:

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

為什么在多路復用器中不能直接根據路由取到視圖函數HandlerFunc然后加括號執行呢?

反而還要多此一舉實現Handler接口,然后將函數包裝后HandlerFunc(f).ServeHTTP(w,r)調用呢。

價值

既能夠將普通的函數類型(需類型轉換)作為參數,也可以將結構體作為參數,使用更為靈活,可讀性也更好,這就是接口型函數的價值。

實例1(net/http)

可以 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", http.HandlerFunc(home))
?? ?// http.HandlerFunc(home)->HandlerFunc->默認的多路復用器會調用它的ServeHTTP()方法
?? ?_ = http.ListenAndServe("localhost:8000", nil)
}

另外一個函數 http.HandleFunc,HandleFunc 的定義如下:

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

第二個參數是一個普通的函數類型,

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

http.ListenAndServe 的第二個參數也是接口類型 Handler,使用了標準庫 net/http 內置的路由,因此傳入的值是 nil。

如果這個地方傳入的是一個實現了 Handler 接口的結構體,就可以完全托管所有的 HTTP 請求,后續怎么路由,怎么處理,請求前后增加什么功能,都可以自定義了。慢慢地,就變成了一個功能豐富的 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)
}

假設有一個方法:

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

如何給該方法傳參呢?

方式一:GetterFunc 類型的函數作為參數(匿名函數)

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

方式二:普通函數

func test(key string) ([]byte, error) {
?? ?return []byte(key), nil
}

func main() {
? ? GetData(GetterFunc(test), "hello")
}

將 test 強制類型轉換為 GetterFunc,GetterFunc 實現了接口 Getter,是一個合法參數。這種方式適用于邏輯較為簡單的場景。

方式三:實現了 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() {
?? ?GetData(new(DB), "hello")
}

DB 實現了接口 Getter,也是一個合法參數。這種方式適用于邏輯較為復雜的場景,如果對數據庫的操作需要很多信息,地址、用戶名、密碼,還有很多中間狀態需要保持,比如超時、重連、加鎖等等。這種情況下,更適合封裝為一個結構體作為參數。

這樣,既能夠將普通的函數類型(需類型轉換)作為參數,也可以將結構體作為參數,使用更為靈活,可讀性也更好,這就是接口型函數的價值。

總結

原文鏈接:https://blog.csdn.net/General_zy/article/details/128822178

欄目分類
最近更新