这个Go函数类型”HandlerFunc”是如何工作的,来自标准库”net/http”。

huangapple go评论74阅读模式
英文:

How does this Go function type "HandlerFunc" work, from the standard library "net/http"

问题

我对HTTP包中的这段代码感到困惑:

type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

为什么ServeHTTP方法的签名与其类型完全相同 - 这有什么意义?

测试后,我发现如果将一个随机函数(foo)传递给HandlerFunc

var bar = HandlerFunc(foo)

bar将成为一个具有foo作为其ServeHTTP方法的HandlerFunc实例。现在我真的对这是如何工作感到困惑。

如果一个类型上有多个方法,我如何知道哪个方法将附加到新实例上,以及使用什么名称或顺序?

英文:

I'm confused about this bit of code from the HTTP package:

type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

Why does the ServeHTTP method have the exact same signature as it's type - what's the point?

 

Testing, I discovered that if I pass a random function (foo) to the HandlerFunc:

var bar = HandlerFunc(foo)

bar becomes an instance of HandlerFunc with foo as its ServeHTTP method. Now I'm really confused about how on earth this works.

If I have more than one methods on a type, how do I know which one is going to be attached to the new instance and with what name or order?

答案1

得分: 9

这种方法允许您在期望Handler的上下文中使用函数。

发生的情况是,有一个Handler接口:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

并且声明了各种函数来接受声明为属于此接口的参数的参数 - 例如:

func TimeoutHandler(h Handler, ns int64, msg string) Handler {
    f := func() <-chan int64 {
        return time.After(ns)
    }
    return &timeoutHandler{h, f, msg}
}

这意味着当您调用此类函数时,必须传入属于满足此接口的类型的对象,也就是说,具有适当签名的ServeHTTP方法的类型。 (在Go中,与某些语言不同,类型不需要显式实现接口,它只需要具有接口指定的方法。)

所以,您引用的代码片段:

type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

创建了一个基于func(ResponseWriter, *Request)的类型HandlerFunc,但通过使用具有适当签名的ServeHTTP方法来增加了该类型,以便满足Handler接口。此ServeHTTP方法只是调用函数本身。因此,如果f是具有正确签名的函数,您可以编写类似于以下内容的代码:

var h HandlerFunc = f // h == f,但转换为HandlerFunc
// 以满足Handler接口。
TimeoutHandler(h, 1000000, "timed out")

为了澄清一些关于此的事情:

经过测试,我发现如果将一个随机函数(foo)传递给HandlerFunc

var bar = HandlerFunc(foo)

bar将成为具有foo作为其ServeHTTP方法的HandlerFunc实例。现在我真的对这是如何工作的感到困惑。

首先,更正确的说法是您已经将一个随机函数foo转换为类型HandlerFunc,而不是将函数传递给HandlerFunc,好像HandlerFunc是一个函数。(HandlerFunc(foo)表示类型转换;您也可以写var bar HandlerFunc = foo并让转换隐式发生。)

其次,更正确的说法是bar具有一个调用fooServeHTTP方法,而不是foo本身实际上ServeHTTP方法。

这样说清楚了吗?

英文:

This approach allows you to use a function in a context that's expecting a Handler.

What happens is, there's a Handler interface:

	type Handler interface {
		ServeHTTP(ResponseWriter, *Request)
	}

and various functions are declared to accept parameters that are declared to belong to this interface &mdash; for example:

	func TimeoutHandler(h Handler, ns int64, msg string) Handler {
		f := func() &lt;-chan int64 {
			return time.After(ns)
		}
		return &amp;timeoutHandler{h, f, msg}
	}

What this means is that when you invoke such a function, you have to pass in an object belonging to a type that satisfies this interface, which is to say, a type that has a ServeHTTP method with the appropriate signature. (In Go, unlike some languages, a type doesn't need to explicitly implement an interface, it just needs to have the methods specified by the interface.)

So, the code-snippet that you quote:

type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

creates a type HandlerFunc that's based on func(ResponseWriter, *Request), but augments the type with a method called ServeHTTP with an appropriate signature, so that it satisfies the Handler interface. This ServeHTTP method just calls the function itself. So, if f is a function with the right signature, you could write something like this:

var h HandlerFunc = f    // h == f, but converted to a HandlerFunc
                         // so it satisfies the Handler interface.
TimeoutHandler(h, 1000000, &quot;timed out&quot;)

To clarify a few things about this:

> Testing, I discovered that if I pass a random function (foo) to the HandlerFunc:
> <pre>var bar = HandlerFunc(foo)</pre>
> bar becomes an instance of HandlerFunc with foo as its ServeHTTP method. Now I'm really confused about how on earth this works.

Firstly, it's more correct to say that you've converted a random function foo to type HandlerFunc, rather than that you've passed the function to HandlerFunc as though HandlerFunc were a function. (The HandlerFunc(foo) notation is a typecast; you could just as well write var bar HandlerFunc = foo and let the conversion happen implicitly.)

Secondly, it's more correct to say that bar has a ServeHTTP method that invokes foo, than that foo itself actually is the ServeHTTP method.

Does that make sense?

huangapple
  • 本文由 发表于 2012年1月1日 06:31:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/8690900.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定