英文:
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
具有一个调用foo
的ServeHTTP
方法,而不是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 — for example:
func TimeoutHandler(h Handler, ns int64, msg string) Handler {
f := func() <-chan int64 {
return time.After(ns)
}
return &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, "timed out")
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论