将一个函数包装在函数类型中有什么意义?

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

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

两个主要原因:

  1. 在接收函数作为参数时更加方便:

     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)) { ... }
    
  2. 当你想要给类型附加方法时。

    在你的例子中,http.HandlerFunc 有一个附加的方法 ServeHTTP。这使得该函数满足 http.Handler 接口。只有命名类型才能附加方法。

并且回答你相关的问题:

> 如果我们想要一个类型暴露一个方法,为什么不创建一个结构类型并将方法添加到其中呢?

因为没有必要这样做。标准库本来可以选择采用你的建议:

    type HandlerFunc struct {
        Func func(ResponseWriter, *Request)
    }

但那样会更冗长,使用和阅读起来更困难。使用这种方式,你需要调用:

    http.HandlerFunc{Func: fn}

而不是更简单的:

    http.HandlerFunc(fn)

所以没有理由增加不必要的复杂性。

英文:

Two main reasons:

  1. 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)) { ... }
    
  2. 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 the http.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.

huangapple
  • 本文由 发表于 2017年3月15日 16:41:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/42804766.html
匿名

发表评论

匿名网友

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

确定