Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

go

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).
like image 943
user218867 Avatar asked Oct 15 '25 07:10

user218867


1 Answers

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

like image 157
leaf bebop Avatar answered Oct 18 '25 01:10

leaf bebop



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!