HandlerFunc(f) 如何将函数转换为接口类型?

Eri*_*ang 4 go

当检查以下代码时,对从函数到接口的类型转换产生疑问。

\n\n
\n\n

代码

\n\n

http_hello.go:

\n\n
package main\n\nimport (\n    "fmt"\n    "log"\n    "net/http"\n)\n\n// hello http,\nfunc helloHttp() {\n    // register handler,\n    http.Handle("/", http.HandlerFunc(helloHandler))\n\n    // start server,\n    err := http.ListenAndServe(":9090", nil)\n    if err != nil {\n        log.Fatal("ListenAndServe:", err)\n    }\n\n}\n\n// handler function - hello,\nfunc helloHandler(w http.ResponseWriter, r *http.Request) {\n    fmt.Fprintf(w, "Hello, you\'ve requested: %s\\n", r.URL.Path)\n}\n\nfunc main() {\n    helloHttp()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

上面的代码有效。

\n\n

(然后我尝试编写一个小程序来检查这是否是一个通用功能,但它不起作用,请检查以下代码)

\n\n

func_to_intf.go:

\n\n
package main\n\nimport (\n    "fmt"\n)\n\n// an interface,\ntype Adder interface {\n    add(a, b int) int\n}\n\n// alias of a function signature,\ntype AdderFunc func(int, int) int\n\n// a simple add function,\nfunc simpleAdd(a, b int) int {\n    return a + b\n}\n\n// call Adder interface to perform add,\nfunc doAdd(a, b int, f Adder) int {\n    return f.add(a, b)\n}\n\nfunc funcToIntf() {\n    fa := AdderFunc(simpleAdd)\n    fmt.Printf("%#v, type: %T\\n", fa, fa)\n\n    a, b := 1, 2\n    sum := doAdd(a, b, fa)\n    fmt.Printf("%d + %d = %d\\n", a, b, sum)\n}\n\nfunc main() {\n    funcToIntf()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
\n

./func_to_intf.go:30:14:无法在 doAdd 的参数中使用 fa(AdderFunc 类型)作为 Adder\n 类型:AdderFunc 未实现 Adder(缺少 add\n 方法)

\n
\n\n
\n\n

问题

\n\n
    \n
  1. http.HandlerFunc(helloHandler)获取 type 的值http.Handler,因为这就是所http.Handle()期望的,这是正确的吗?
  2. \n
  3. 如果是,则意味着它将函数转换为接口类型的值,这是如何发生的?\n\n
      \n
    • 这是Go的内置功能吗?
      \n我做了一个测试(如上所述func_to_intf.go),但似乎没有。
    • \n
    • 或者,是http.HandlerFunc\ 的特殊实现实现的吗?
    • \n
  4. \n
\n\n
\n\n

@Update - 摘要

\n\n

(虽然答案很好地解决了问题,但经过审查和更多测试后,需要其他几个功能才能完全消除最初的疑问,如下所示。)

\n\n
    \n
  • 函数类型。
    \n函数就是值,并且它有类型。\n函数类型可以通过函数签名上的关键字
    来定义。\ne.gtype
    type AdderFunc func(int, int) int
  • \n
  • 函数上的类型转换器\xef\xbc\xb4(v)
    \n任何函数都可以转换为具有相同签名的函数类型,只需通过T(v),使用函数类型名称为T,实际函数为v
    \n然后当调用新值时,v将调用实际函数。
    \ne.g fa := AdderFunc(simpleAdd)
    \n (在提出问题之前,这对我来说很模糊,这是我感到困惑的主要原因之一)
  • \n
\n

lea*_*bop 5

这是一个简单的类型转换。

在 Go 中,除了 s 之外,您还可以定义自定义类型struct。在本例中,http.HandlerFunc是函数类型,func(http.ResponseWriter,*http.Request)。由于您的函数与自定义类型具有相同的基础类型(签名),因此可以将其转换为自定义类型。

此外,代码可以在自定义类型上定义方法,无论它是什么基础类型,也无论它struct是否是 a。在这种情况下,http包定义了ServeHTTP它的方法,当然,它只是调用函数本身。

您可以在这里阅读源代码:https://golang.org/src/net/http/server.go ?s=58384:58444#L1936

至于示例代码中的加法器,您可以执行相同的操作:在 上定义一个方法AdderFunc

func (a AdderFunc) add(x, y int) int {
    return a(x, y)
}
Run Code Online (Sandbox Code Playgroud)

游乐场: https: //play.golang.org/p/5mf_afHLQA2