英文:
What's the point in wrapping a function in a function type?
问题
我是你的中文翻译助手,以下是翻译好的内容:
我对golang还不熟悉,偶尔看到一些将函数包装在函数类型中的代码。在http包中,我们也有这样的情况:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
我很好奇其中的原因。如果我们想要一个公开方法的类型,为什么不创建一个结构体类型并将方法添加到其中呢?
英文:
I am new to golang and I've seen occasionally some code that wraps a function inside a function type. In http package we have this as well:
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
I'm curious to know the reason behind. If we want to have a type that exposes a method why don't we create a struct type and add the method to it?
答案1
得分: 7
两个主要原因:
-
在接收函数作为参数时更加方便:
type LongFuncSig func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error) func DoSomething(fn LongFuncSig) { ... } func DoSomethingElse(fn LongFuncSig) { ... } func DoYetAnotherThing(fn LongFuncSig) { ... }这种方式比下面的方式更易读,也更不容易出错:
func DoSomething(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } func DoSomethingElse(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } func DoYetAnotherThing(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } -
当你想要给类型附加方法时。
在你的例子中,
http.HandlerFunc有一个附加的方法ServeHTTP。这使得该函数满足http.Handler接口。只有命名类型才能附加方法。
并且回答你相关的问题:
> 如果我们想要一个类型暴露一个方法,为什么不创建一个结构类型并将方法添加到其中呢?
因为没有必要这样做。标准库本来可以选择采用你的建议:
type HandlerFunc struct {
Func func(ResponseWriter, *Request)
}
但那样会更冗长,使用和阅读起来更困难。使用这种方式,你需要调用:
http.HandlerFunc{Func: fn}
而不是更简单的:
http.HandlerFunc(fn)
所以没有理由增加不必要的复杂性。
英文:
Two main reasons:
-
Convenience when receiving functions as arguments:
type LongFuncSig func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error) func DoSomething(fn LongFuncSig) { ... } func DoSomethingElse(fn LongFuncSig) { ... } func DoYetAnotherThing(fn LongFuncSig) { ... }Is much more readable, and less error-prone than:
func DoSomething(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } func DoSomethingElse(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } func DoYetAnotherThing(fn func(a int, b *int, c string, d *SomeWeirdThing, f map[string]*Foo, g ...interface{}) (*Result, error)) { ... } -
When you want to attach methods to the type.
In your example,
http.HandlerFunchas an attached method,ServeHTTP. This causes the function to satisfy thehttp.Handlerinterface. It's only possible to attach methods to named types.
And to answer your related question:
> If we want to have a type that exposes a method why don't we create a struct type and add the method to it?
Because there's no reason to do do that. The standard library could have chosen to take your suggestion with:
type HandlerFunc struct {
Func func(ResponseWriter, *Request)
}
But that's far more verbose, and harder to use and read. To use that, you'd then have to call:
http.HandlerFunc{Func: fn}
instead of the much simpler:
http.HandlerFunc(fn)
So there's no reason to add unnecessary complexity.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论