英文:
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.HandlerFunc
has an attached method,ServeHTTP
. This causes the function to satisfy thehttp.Handler
interface. 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论