簡體   English   中英

為什么這個函數的參數沒有被調用為 function?

[英]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作為參數調用的。

但是,當運行此代碼時,執行順序是:

  1. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM