Tuesday, November 27, 2018

go - How HandlerFunc(f) convert a function to an interface type?



When check following code, got a doubt with type convert from function to interface.







Code



http_hello.go:



package main

import (
"fmt"
"log"

"net/http"
)

// hello http,
func helloHttp() {
// register handler,
http.Handle("/", http.HandlerFunc(helloHandler))

// start server,
err := http.ListenAndServe(":9090", nil)

if err != nil {
log.Fatal("ListenAndServe:", err)
}

}

// handler function - hello,
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
}


func main() {
helloHttp()
}


The above code works.



(Then I tried to write a small program to check is this a general feature, but it won't work, check following code)




func_to_intf.go:



package main

import (
"fmt"
)

// an interface,
type Adder interface {

add(a, b int) int
}

// alias of a function signature,
type AdderFunc func(int, int) int

// a simple add function,
func simpleAdd(a, b int) int {
return a + b
}


// call Adder interface to perform add,
func doAdd(a, b int, f Adder) int {
return f.add(a, b)
}

func funcToIntf() {
fa := AdderFunc(simpleAdd)
fmt.Printf("%#v, type: %T\n", fa, fa)


a, b := 1, 2
sum := doAdd(a, b, fa)
fmt.Printf("%d + %d = %d\n", a, b, sum)
}

func main() {
funcToIntf()
}



Output:




./func_to_intf.go:30:14: cannot use fa (type AdderFunc) as type Adder
in argument to doAdd: AdderFunc does not implement Adder (missing add
method)








Questions




  1. http.HandlerFunc(helloHandler) get a value of type http.Handler, since that's what http.Handle() expect, is that correct?

  2. If yes, then means it convert a function into a value of an interface type, how did that happen?


    • Is this a built-in feature of go?
      I did a test (as in func_to_intf.go above), and seems not.

    • Or, is http.HandlerFunc's special implementation achieve that?








@Update - Summary



(Though the answer(s) addressed the questions pretty well, but after reviewing & more testing, there are several other go features required to totally erase the original doubt, as following.)




  • Function type.
    Function is value, and it has type.
    Function type could be defined via type keyword on a function signature.
    e.g type AdderFunc func(int, int) int


  • Type convertor T(v) on function.
    Any function could be converted to a function type with the same signature, just via T(v), use function type name as T, and actual function as v.
    Then when the new value is called, the actual function v is called.
    e.g fa := AdderFunc(simpleAdd)
    (this is blur to me before asking the question, and that's one of the main reason I was confused).


Answer



It is a simple type-conversion.



In Go you can define custom type besides structs. In this case, http.HandlerFunc is a function type, func(http.ResponseWriter,*http.Request). Since your function is of the same underlying type (signature) as the custom type, it can be converted to it.



Furthermore, code can define methods on custom type, no matter what underlying type it is, or whether it is a struct or not. In this case, http package defines ServeHTTP method on it, and of course, it just calls the function itself.



You can read the source code here: https://golang.org/src/net/http/server.go?s=58384:58444#L1936




As for the adder in your sample code, you can do the same: Define a method on AdderFunc.



func (a AdderFunc) add(x, y int) int {
return a(x, y)
}


Playground: https://play.golang.org/p/5mf_afHLQA2


No comments:

Post a Comment

plot explanation - Why did Peaches' mom hang on the tree? - Movies & TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...