lnmx
lnmx

Reputation: 11154

How do I convert a go method to a func?

I have a package-level function (Frob) that takes a function as an argument. For the function argument, I want to pass in a method (FrobMethod) with a particular struct instance as the receiver (myFrob).

The only way I've found to accomplish this is to use a func literal/closure that captures the target struct. That requires repeating the func signature and arguments, which seems too verbose. Is there a better way?

package main

import "fmt"

func Frob( frobber func( int ) ( string ) ) {
    fmt.Printf( "Frob %s\n", frobber( 42 ) )
}

type MyFrob struct {
    Prefix string
}

func ( m MyFrob ) FrobMethod( n int ) ( string ) {
    return fmt.Sprintf( "%s %d", m.Prefix, n )
}

func main() {

    myFrob := MyFrob { Prefix: "Hello" }

    // C# allows something like this:
    //
    //Frob( myFrob.FrobMethod )

    Frob( func ( n int ) ( string ) {
        return myFrob.FrobMethod( n )
    } )
}

...a real-world example of this is HandleFunc in net/http.

Upvotes: 4

Views: 560

Answers (3)

lnmx
lnmx

Reputation: 11154

As of Go 1.1, the C#-style method reference works:

Frob( myFrob.FrobMethod )

See the Method expressions section of the Go Language Specification.

Upvotes: 1

jdi
jdi

Reputation: 92559

While Go does allow you to create anonymous function assignments to variables and pass them around, another way to approach this problem is to make use of interfaces.

package main

import "fmt"

type Frobber interface {
    Frob(int) string
}

type MyFrob struct {
    Prefix string
}

func (m MyFrob) Frob(n int) string {
    return fmt.Sprintf("%s %d", m.Prefix, n)
}

func Frob(f Frobber) {
    fmt.Printf("Frob %s\n", f.Frob(42))
}

func main() {
    myFrob := MyFrob {Prefix: "Hello"}
    Frob(myFrob)
}

In an object oriented language, you would be able to just pass a method around, but Go isn't OO. You have to start your brain over from the beginning and not try to write the code like you would in other languages. I have that same problem coming from Python.

By the way, I love Go and am actively trying to improve my skills with it as a tool in my tool belt. In response to @Jeremy in the comments, I am only stating that Go is not OO because its not firmly supported to be such by the Go team, and its more commonly referred to as procedural, and, having a mixture of elements from other languages that are themselves considered to be OO

Upvotes: 1

user811773
user811773

Reputation:

In my opinion, idiomatic Go should use an interface instead of a function in this case:

package main

import "fmt"

type Frobber interface {
    FrobMethod(int) string
}

func Frob(frobber Frobber) {
    fmt.Printf("Frob %s\n", frobber.FrobMethod(42))
}

type MyFrob struct {
    Prefix string
}

func (m MyFrob) FrobMethod(n int) string {
    return fmt.Sprintf("%s %d", m.Prefix, n)
}

func main() {
    myFrob := MyFrob{Prefix: "Hello"}
    Frob(myFrob)
}

The function HandleFunc in net/http is a wrapper for function Handle which takes an interface argument.

Upvotes: 4

Related Questions