DEV Community

Cover image for Functions
Samuel Grasse-Haroldsen
Samuel Grasse-Haroldsen

Posted on

Functions

Function Declaration

Declaring functions in Go is very straightforward. In fact, we have already declared a function in all of our programs so far. The main function is required in every binary executable (a program we want to run on its own, not a library we want to share). As with loops and conditional statements, we need to follow the "one true brace style."

package main

import "fmt"

func main() {
    fmt.Println("We are finally talking about functions!")
}
Enter fullscreen mode Exit fullscreen mode

Let's go ahead and declare a more complicated function outside of main. add will take two integers and return an integer.

package main

import "fmt"

func add(x, y int) int {
    return x + y
}

func main() {
    sum := add(2, 3)
    fmt.Println("The sum of 2 + 3 is", sum)
}
Enter fullscreen mode Exit fullscreen mode
  1. func add
    With the keyword func we are telling the Go compiler add is a function.

  2. (x, y int)
    In the parentheses we are declaring the names of our parameters x and y. We also need to tell the compiler what type of arguments to expect. Here we are saying the arguments should both be of type int. We could alternatively declare each parameter type like this: func add(x int, y int).

  3. int {
    After our list of parameters we need to declare what type of data add will return, in this case int. If we don't return anything in function we leave this part blank ex) func printLine(msg string) {

  4. return x + y
    In our function body we return the value of x and y added.

NOTE: There is no implicit return like in Ruby.

Returning

In Go you can return multiple values!

func addAndSubtract(x, y int) (sum, difference int) {
    sum = x + y
    difference = x - y
    return sum, difference
}
Enter fullscreen mode Exit fullscreen mode

Here we are still taking two ints, but now we are returning their sum and their difference! Note the use of parentheses when we return more than one value (this is necessary). In this example we can also see that Go allows us to name our return values; though, it is not necessary. We could have alternatively written this: func addAndSubtract(x, y int) (int, int). When we name our return values they are initialized to their zero value (we don't need to explicitly initialize them in our function body).

NOTE: It is important to remember that although we can always return any number of values in Go, this functionality should not be abused as it can lead to avoidable complexity.

First Class Functions

Go functions are first class. This means you can assign them to variables, send them as arguments to other functions, and even return functions. There are also function literals in Go AKA anonymous functions, as well as closures. JavaScript developers should feel right at home with this functionality.

package main

import "fmt"


func addNumber(number int) func(int) int {
    return func(num int) int {
        return number + num
    }
}

func main() {
    add42 := addNumber(42)
    fmt.Println(add42(10)) //prints 52
}
Enter fullscreen mode Exit fullscreen mode

This example demonstrates how to write a function literal, return a function, assign it to a variable, and create a closure. Let's go through the code step-by-step.

  1. func addNumber(number int) func(int) int {
    We are declaring our function addNumber here. It will take an argument called number of type int and addNumber will return a function. It may seem superfluous, but we must tell the Go compiler what kind of function addNumber will return. func(int) int is simply the type signature for the function we are going to return. The function we are returning will take an int as a parameter and return an int value.

  2. return func(num int) int {
    This is where we are returning our anonymous function (called a function literal in Go). It will take an int as an argument and return an int value.

  3. return number + num
    We are simply returning the parent function's number argument added to the function literal's argument num.

  4. add42 := addNumber(42)
    Here we are assigning the return value of addNumber (our function literal) and assigning it to the variable add42. add42 now points to a function that will add whatever number we pass it with 42 because that was the number we passed to addNumber when we initialized add42. This is where the closure is created.

Simplifying With Custom Types

In a statically typed language we need to tell our compiler what kind of data our variable should hold. Go has a number of built-in basic types such as int, float, bool, and string, but we can also declaring our own types! This will make our last example a little cleaner. Enter another reserved word: type!

package main

import "fmt"

type addClosureFunc func(int) int

func addNumber(number int) addClosureFunc {
    return func(num int) int {
        return number + num
    }
}

func main() {
    add42 := addNumber(42)
    fmt.Println(add42(10)) //prints 52
}
Enter fullscreen mode Exit fullscreen mode

It is extremely simple to declare a new type. You simply need a name for the type: addClosureFunc and the underlying implementation func(int) int. We can even add names to our parameter and return value if we want, just to make things a little more clear.

type addClosureFunc func(sum int) (num int)
Enter fullscreen mode Exit fullscreen mode

Conclusion

With the power to declare functions, pass them around like any other variable, and create our own types, we can really see the power Go gives us to create very maintainable, easy-to-follow code. Next week we will talk about methods.

Top comments (0)