Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with function types in Go

Tags:

I wanted to create a function of a certain type. I've found one way to do it, but there must be other, cleaner and nicer ways that do not include using var. What are the alternative ways to declare the function english of type Greeting?

package main

import "fmt"

type Greeting func(name string) string

func (g Greeting) exclamation(name string) string {
    return g(name) + "!"
}

var english = Greeting(func(name string) string {
    return "Hello, " + name
})

func main() {
    fmt.Println(english("ANisus"))
    fmt.Println(english.exclamation("ANisus"))  
}

In the example above, I can't exchange var english = Greeting... with english := Greeting..., nor can I remove the Greeting(func ...) and just have the func stand alone since then I won't be able to access the exclamation method.

like image 714
ANisus Avatar asked Feb 22 '12 16:02

ANisus


People also ask

What is function type in Go?

A function type denotes the set of all functions with the same parameter and result types.

How do you use functions in Golang?

In Golang, we declare a function using the func keyword. A function has a name, a list of comma-separated input parameters along with their types, the result type(s), and a body. The input parameters and return type(s) are optional for a function. A function can be declared without any input and output.

What does func () mean in Golang?

func: It is a keyword in Go language, which is used to create a function. function_name: It is the name of the function. Parameter-list: It contains the name and the type of the function parameters. Return_type: It is optional and it contain the types of the values that function returns.

Can you pass functions in Go?

Go programming language allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.


2 Answers

If mentioning var is your main problem, you can drop it easily, by changing = into :=, like this:

english := Greeting(func(name string) string {
    return ("Hello, " + name);
})

But you don't even have to cast your function into Greeting. The spec says this about function types:

A function type denotes the set of all functions with the same parameter and result types.

And this about type identity:

Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.

This means that each function has its own function type. If two functions have the same signature (parameter and result types), they share one function type. By writing type Greeting func... you're just giving a name to a particular function type, not defining a new one.

So the following code works, and I hope shows the right way to work with function types in Go:

package main

import "fmt"

type Greeting func(name string) string

func say(g Greeting, n string) { fmt.Println(g(n)) }

func french(name string) string { return "Bonjour, " + name }

func main() {
        english := func(name string) string { return "Hello, " + name }

        say(english, "ANisus")
        say(french, "ANisus")
}

Notice that I also dropped semicolon and parenthesis from your english function. Go developers don't use these punctuations if they don't have to.

UPDATE: Now that you've provided a sample code I can clearly understand the problem.

For this purpose your code is good enough and there are not much other ways of doing it. If you like you can cast just before calling the method:

english := func(name string) string { return "Hello, " + name }
Greeting(english).exclamation("ANisus")

But I'm not sure this is an improvement. I'm just saying that for what you want to do there does not seem to be other ways to write the code.

That is, if we don't want to change your types. I mean, the whole idea of calling a method on a function type seems a little weird. Not that it's wrong, but a little rare. Another way of achieving the same effect in a more usual way is through a struct type and having a field for the function. Something like this:

package main

import "fmt"

type Greeting struct {
    say func(name string) string
}

func newGreeting(f func(string) string) *Greeting {
    return &Greeting{say: f}
}

func (g *Greeting) exclamation(name string) string { return g.say(name) + "!" }

func main() {
    english := &Greeting{say: func(name string) string {
        return "Hello, " + name
    }}

    french := newGreeting(func(name string) string {
        return "Bonjour, " + name
    })

    fmt.Println(english.exclamation("ANisus"))
    fmt.Println(french.exclamation("ANisus"))
}

Here english and french show two different ways of coding the same thing. Again, I'm not saying that this is the better solution, but a more usual and more flexible way of achieving the same effect.

like image 194
Mostafa Avatar answered Oct 13 '22 20:10

Mostafa


Trying to separate issues here,

type Greeting func(string) string

func english(name string) string {
    return return "Hello, " + name
}

func main() {
    var g Greeting
    g = english
    fmt.Println(g("ANisus"))
}

Is the way to declare the function english of type Greeting. Notice Greeting is not used in the definition of english, so this may not meet your requirement of declaring a function of a specific type. Otherwise, sorry, there is no way in Go to define a function of a specific (that is, separately defined) type. It might be nice to type something like,

english := Greeting {
    return return "Hello, " + name
}

but no, there is no way in Go. The declaration of english can't use Greeting, and must repeat the function signature. Instead the requirement that english is of type Greeting is made only in the assignment

g = english

g is declared of type Greeting. If english isn't the same type, the line won't compile.

Beyond the issue of repeating the type signature--the issues of methods, for example--it's not clear if you're still looking for other ways to organize the functionality of your example. It can certainly be done other ways. A bigger example though, maybe posed as a separate question, would help.

like image 26
Sonia Avatar answered Oct 13 '22 20:10

Sonia