[英]Why is this function's argument not being invoked as a function?
這是我當前閱讀材料“Hands-On Restful Web Services With Go”中的完整示例,來自 Packt。
func filterContentType(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("Currently in the check content type middleware")
// Filtering requests by MIME type
if r.Header.Get("Content-type") != "application/json" {
w.WriteHeader(http.StatusUnsupportedMediaType)
w.Write([]byte("415 - Unsupported Media Type. Please send JSON"))
return
}
handler.ServeHTTP(w, r)
})
}
func setServerTimeCookie(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Setting cookie to every API response
cookie := http.Cookie{Name: "ServerTimeUTC", Value: strconv.FormatInt(time.Now().Unix(), 10)}
http.SetCookie(w, &cookie)
log.Println("Currently in the set server time middleware")
handler.ServeHTTP(w, r)
})
}
func handle(w http.ResponseWriter, r *http.Request) {
// Check if method is POST
if r.Method == "POST" {
var tempCity city
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&tempCity)
if err != nil {
panic(err)
}
defer r.Body.Close()
// Your resource creation logic goes here. For now it is plain print to console
log.Printf("Got %s city with area of %d sq miles!\n", tempCity.Name, tempCity.Area)
// Tell everything is fine
w.WriteHeader(http.StatusOK)
w.Write([]byte("201 - Created"))
} else {
// Say method not allowed
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("405 - Method Not Allowed"))
}
}
func main() {
originalHandler := http.HandlerFunc(handle)
http.Handle("/city", filterContentType(setServerTimeCookie(originalHandler))) // !
http.ListenAndServe(":8000", nil)
}
該程序僅由主要的 function 和其他 3 個函數組成,它們的邏輯是任意的,只是從我書中的示例中復制而來。
在底部,我用“!”評論了 , filterContentType
使用的參數本身是 function ( setServerTimeCookie
),看起來它是用originalHandler
作為參數調用的。
但是,當運行此代碼時,執行順序是:
filterContentType
2. setServerTimeCookie
3. originalHandler
這與我對使用函數作為 arguments 的理解背道而馳。 我認為setServerTimeCookie
將是第一個執行的,但事實並非如此; 它的行為就像一個未調用的 function。
這引出了我的問題,是什么導致setServerTimeCookie
推遲執行,盡管語法表明它被調用為filterContentType
的參數?
我試圖簡化事情以供自己理解:
func main() {
one(two(three))
}
func one(f func()) {
fmt.Println("ONE\n")
f()
}
func two(f func()) {
fmt.Println("TWO\n")
f()
}
func three(){
fmt.Println("THREE\n")
}
這段代碼沒有構建,我留下了錯誤: two(three) used as value
- 這告訴我正在調用two
,這與書中的示例不同。
又有什么區別,為什么書中的例子不先調用setServerTimeCookie
呢? 我唯一的假設是它與http.HandlerFunc
的實現有關,所以也許我應該從那里開始。
任何能快速推進我的理解的見解將不勝感激。
這不會編譯,因為two(three)
不返回值。
我假設您想在這種情況下返回 function 閉包,因此要修復:
func two(f func()) func() {
return func() {
fmt.Println("TWO\n")
f()
}
}
https://go.dev/play/p/vBrAO6nwy4X
回到你關於setServerTimeCookie
的問題,它使用return http.HandlerFunc(fn)
。 查看http.HandlerFunc的源代碼發現它實際上是一個類型定義 - 而不是傳統的 function 調用。 恕我直言,它實際上是go
標准庫中最強大且被低估的四行代碼:
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
通過創建http.HandlerFunc
的這個值,它隱含地是一個http.Handler
,因為它提供了ServeHTTP
方法。 因此,這允許根據請求調用此方法——這正是 web 服務的設計目的:調用處理程序時將調用底層 function f
。
因為在表達式one(two(three))
function 中, two
沒有作為 function 引用傳遞。 取而代之的是 function two
用參數tree
調用,這不是one
期望的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.