Go Functions & Lambdas Tutorial

In this Go tutorial we learn how to group and reuse sections of our code with functions. We learn how to define and invoke functions, how to add parameters and arguments and how to return values.

We also learn how to initialize variables with functions as well as anonymous functions, known as lambda expressions, that don't have identifiers.

Lastly, we quickly discuss methods.

What is a function

A function allows us to reuse sections of code throughout our Go app without having to rewrite those sections each time.

As an example, let’s consider some code logic that determines if a number is even or odd.

Example:
package main

import "fmt"

func main() {

    num := 5;

    if num % 2 == 0 {
        fmt.Printf("%d is an even number\n", num)
    } else {
        fmt.Printf("%d is an odd number\n", num)
    }
}

The example above will check if a number is even or odd. It divides the number by 2 and if there’s anything left over, the number is odd. Otherwise, the number is even.

This functionality can be placed inside a function, enabling us to reuse it anywhere in our code as much as we want.

Go provides us with multiple types of functions:

  • Standard functions with an identifier
  • Anonymous functions (lambdas)

How to define a standard Go function

The standard Go function consists of 5 parts.

  • The keyword func
  • An identifier
  • A parameter list
  • A return type
  • A code block (body)
Syntax:
func function_name( parameter_list ) return_type {

    // body of the function
}

Let’s start with an example of the most basic function and add the extra parts from there.

Example:
package main

import "fmt"

func main() {}

func consoleLog() {

    fmt.Println("Hello from inside a function")
}

In the example above, we defined a function called consoleLog. It has no parameters or return type and it will simply print a message to the console.

Note that we defined the custom function outside of the main function.

If we run the example above, nothing happens. That’s because we’ve defined the function but we haven’t used it anywhere yet. Let’s look at that next.

How to use (call/invoke) a standard Go function

To call (invoke) a function, we write its name, followed by open and close parentheses.

Even though the parameter list is empty, we still write the parentheses when we invoke the function.

Example:
package main

import "fmt"

func main() {

    consoleLog()
}

func consoleLog() {

    fmt.Println("Hello from inside a function")
}

This time when we run the example above, it prints the message from inside the function.

We can call a function as many times as we need it by invoking it again or putting it in a loop.

Example:
package main

import "fmt"

func main() {

    // multiple calls
    consoleLog()
    consoleLog()

    // looping the calls
    for i:=0; i<3; i++ {
        consoleLog()
    }
}

func consoleLog() {

    fmt.Println("Hello from inside a function")
}

In the example above we call the function twice manually, and three times in the loop.

How to add parameters and arguments to a standard Go function

Now that we know how to define a basic function and call it, we can add some input parameters.

Parameters allow us to pass values to the function, and have those values influence the logic in the body. Parameters are optional, but also immensely useful.

Parameters are written inside the parentheses of the function. Multiple parameters are separated with a comma.

Syntax:
func function_name( param_name_1 type, param_name_2 type, ... ) {

    // param_name_1 and param_name_2 are now
    // available to be used inside the body
}

We must include a data type for the parameter or the compiler will raise a ‘paramName undefined’ error.

Example:
package main

import "fmt"

func main() {}

func consoleLog(msg string) {

    fmt.Println(msg)
}

In the example above, we added a parameter called msg of type string. Then we added it to the Println() statement.

If we call the function now, and write something between the parentheses, it will be placed where the msg parameter is in the body.

Example:
package main

import "fmt"

func main() {

    consoleLog("Hello")
}

func consoleLog(msg string) {

    fmt.Println(msg)
}

The value we pass to a parameter list, like the word ‘Hello’ above, is known as an argument.

When a parameter exists in a function, we must pass a value to it when the function is called.

As mentioned before, we can alse use multiple parameters in a function.

Example:
package main

import "fmt"

func main() {

    greeting("John Doe", 25)
}

func greeting(name string, age int) {

    fmt.Printf("Hi, my name is %s and I'm %d years old", name, age)
}

This time we have more than one parameter, each of different types.

The arguments in the function call must match the types specified in the parameter list.

How to return values from a standard Go function

Functions in Go can return one or more values from its body when called.

As an example, let’s consider a function that adds two numbers together. We would need to temporarily store the result of the addition in order to reuse it if we need to later on.

To return values from a function, we typically need three things:

  1. The type of value(s) we are going to return.
  2. The actual value(s) we want to return.
  3. The return keyword.

In Go we specify the return type after the parentheses, but before the open curly brace of the code block.

Syntax:
func name( params ) return_type {

    return value
}
Example:
package main

import "fmt"

func main() {

    result := add(5, 3)

    fmt.Println(result)
}

func add(num1 int, num2 int) int {

    return num1 + num2
}

In the example above we want to return two integers added together, so we know the return type will be an int as well.

In the body of the function we use the return keyword to tell the compiler to output the addition from the function.

When we call the function, we store the value that the function outputs in a variable called result and then print it out to the console.

To return multiple values, we separate their types with a comma and wrap them in parentheses. We also separate the return values themselves with commas.

Syntax:
func name( params ) (return_type_1, return_type_2) {

    return value_1, value_2
}

If we don’t wrap multiple return types in parentheses, the compiler will raise a ‘unexpected comma’ error.

We also need to remember that if we want to return multiple values, we have to create multiple variables to store them.

Example:
package main

import "fmt"

func main() {

msg1, msg2 := swap("Hello World", "Hello There")

    fmt.Printf("msg1: %s\nmsg2: %s", msg1, msg2)
}

func swap(a string, b string) (string, string) {

    return b, a
}

In the example above, we made a function that will swap two string values and return them both.

We take in first value a, then value b, but we return first value b, then a, effectively swapping the two values.

When we call the function, we assign the output from the function to two separate variables inline.

The first argument is ‘Hello World’, the second is ‘Hello There’. The function swaps the two so that ‘Hello There’ is stored in the first variable, and ‘Hello World’ is stored in the second as shown in the output.

Output:
msg1: Hello There
msg2: Hello World

Custom Function: isEven()

Now that we know how to create a full standard function, we can create one for the code at the beginning of this tutorial.

As a mini-exercise, see if you can create a function from the following logic.

Example:
package main

import "fmt"

func main() {

    num := 5;

    if num % 2 == 0 {
        fmt.Printf("%d is an even number\n", num)
    } else {
        fmt.Printf("%d is an odd number\n", num)
    }
}

If you get stuck, take a look at our solution below.

Example:
package main

import "fmt"

func main() {

    isEven(5)
    isEven(80)
    isEven(-125)
    isEven(23786)
}

func isEven(num int) {

    if num % 2 == 0 {
        fmt.Printf("%d is an even number\n", num)
    } else {
        fmt.Printf("%d is an odd number\n", num)
    }
}

How to use a standard Go function as a value

Go provides us with the ability to initialize a variable directly with a function, meaning the function is the variable’s value.

We can then use the variable name, instead of a function name to call the function.

Syntax:
// initialization
variable_name := func(parameters) type {

    // body
    return
}

// call
variable_name(parameters)

Instead of giving the function itself a name, we assign it to a variable. When calling the function we use the variable name.

Example:
package main

import "fmt"

func main() {

    consoleLog := func(msg string) {
        fmt.Println(msg)
    }

    consoleLog("Hello")
}

A benefit of using a function as a value is that we can initialize the function within another, like the example above.

How to use anonymous functions (lambdas)

Go supports anonymous functions (lambdas). Lambda expressions are used when we want to define a function inline without giving it any name.

The way we declare a lambda depends on how we want to use it. It can be defined only, or defined and executed.

Let’s see how to define and execute a lambda.

Syntax:
// defined
func(parameters) {

    // body
}

// defined and executed
func(parameters) {

    // body
} (arguments)

If we want a lambda to be defined without being executed, we only omit its identifier.

If we want the lambda to be defined and executed, we omit its identifier and add an argument list in parentheses after the body’s closing curly brace.

Essentially, the () at the end is what tells the compiler to execute or not execute the lambda.

Example: define and execute
package main

import "fmt"

func main() {

    func(msg string) {

        fmt.Println(msg)
    } ("Hello")
}

In the example above, we define and execute a simple lambda that prints a message to the console.

Example: define only
package main

import "fmt"

func main() {

    // function as value
    consoleLog := returnLambda()
    // invoke lambda that is returned
    consoleLog("Hello")
}

func returnLambda() func(string) {

    // return lambda
    return func(msg string) {

        fmt.Println(msg)
    }
}

In the example above, we create a standard function with a return type of func because we want the standard function to return a lambda function.

We don’t add an argument list this time because we don’t want the lambda to execute inside the function, we just want it to be returned.

Methods

Methods are functions that are linked to types, like structs. We will learn more about them after discussing structures.

If you already know about structures, you can skip directly to the Go Interfaces tutorial.

Summary: Points to remember

  • Functions allow us to group sections of code together for reuse.
  • Function definitions use the func keyword.
  • Even if a function doesn’t have any parameters, we still need to write the paremeter list parentheses both in the definition and the call.
  • To invoke (call) a function, we refer to it by its identifier.
  • We can return one or more values from a function with the return keyword.
  • When returning more than one value, we need to assign them to variables.
  • We can initialize a variable with a function. The variable name then acts as the function name.
  • An anonymous function (lambda) is a function without a name.
  • A lambda can be defined only, or defined and executed by adding an argument list at the end.
  • Methods are functions that are linked to types, allowing us to create OOP like methods.