Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point in wrapping a function in a function type?

Tags:

go

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?

like image 398
Javad M. Amiri Avatar asked Mar 15 '17 08:03

Javad M. Amiri


1 Answers

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.

like image 75
Flimzy Avatar answered Nov 08 '22 15:11

Flimzy