Anonymous Functions in Golang

GolangGolangBeginner
Practice Now

Introduction

In the previous labs, you learned how to write and use named functions, how to organize code into modules, and how to improve code readability by splitting logic into separate functions. In this lab, we will explore anonymous functions, a special type of function that has no name. Anonymous functions are useful when you want to define a small piece of logic "in place" without having to declare a separate, named function. They are particularly helpful for short, self-contained operations, or when you need to pass a function as an argument to another function (like in callbacks). By using anonymous functions, you can write more concise and expressive code.

Key Topics:

  • What anonymous functions are and how to define them
  • Why and when to use anonymous functions
  • Calling anonymous functions without assigning them to a name
  • Passing parameters to anonymous functions and returning values
  • Using anonymous functions as callback functions for more flexible code

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/BasicsGroup(["Basics"]) go(("Golang")) -.-> go/FunctionsandControlFlowGroup(["Functions and Control Flow"]) go/BasicsGroup -.-> go/values("Values") go/BasicsGroup -.-> go/variables("Variables") go/FunctionsandControlFlowGroup -.-> go/functions("Functions") go/FunctionsandControlFlowGroup -.-> go/closures("Closures") subgraph Lab Skills go/values -.-> lab-149099{{"Anonymous Functions in Golang"}} go/variables -.-> lab-149099{{"Anonymous Functions in Golang"}} go/functions -.-> lab-149099{{"Anonymous Functions in Golang"}} go/closures -.-> lab-149099{{"Anonymous Functions in Golang"}} end

Understanding Anonymous Functions

An anonymous function in Go is defined just like a normal function, except it does not have a name. Instead, you can assign it to a variable, pass it as an argument, or immediately execute it after its definition. This makes them well-suited for short, one-off operations, or for passing functions as arguments to other functions. Anonymous functions are particularly useful when a function is needed only once and does not warrant a separate named function. They can help to make your code more readable by keeping logic close to where it's used.

Syntax for an anonymous function:

func(input parameters)(return parameters) {
    // code block
}

This looks similar to defining a regular function, but without the function name.

Comparing it to a regular function declaration:

// Regular function declaration
func functionName(parameters...)(return values...) {
    code block
}

Why use anonymous functions?

  • Conciseness: They allow you to define small pieces of logic without having to create a separate named function, making code more concise.
  • Local Scope: The scope of anonymous functions is within the surrounding function, thus limiting namespace pollution.
  • Flexibility: They can be passed as arguments to other functions or defined and executed immediately.

When to use anonymous functions?

  • When you need a short function that won't be reused elsewhere.
  • As callback functions (we'll see this later).
  • When you want to execute a function immediately (often for initialization).

Creating an Anonymous Function without Parameters

Let’s start with a simple example that prints "hello world" using an anonymous function. First, create a file named anonymous.go in the project directory:

cd ~/project
touch anonymous.go

Open anonymous.go and add the following code:

package main

import "fmt"

func main() {
    // Define an anonymous function and assign it to a variable f
    f := func() {
        fmt.Println("hello world")
    }

    // Call the anonymous function via the variable f
    f()
}

Run the program:

go run anonymous.go

Expected output:

hello world

Here, we defined an anonymous function using the func() { ... } syntax. This function doesn't take any parameters and doesn't return any values. We assigned this anonymous function to the variable f. Then we call the function using f(). This executes the anonymous function and prints "hello world".

Using Parameters in Anonymous Functions

Anonymous functions can accept parameters just like regular functions. Let’s modify our code to pass a string as a parameter.

Replace the contents of anonymous.go with:

package main

import "fmt"

func main() {
    f := func(s string) {
        fmt.Println(s)
    }
    f("hello world")
}

Run the program:

go run anonymous.go

Expected output:

hello world

This time, our anonymous function takes a string parameter s. The func(s string) part defines that the anonymous function takes a parameter named s of type string. When we call f("hello world"), the string "hello world" is passed to the function, which then prints it to the console. This demonstrates how you can pass values into anonymous functions to make them more versatile.

Returning Values from Anonymous Functions

Anonymous functions can also return values. Let’s create an anonymous function that takes two integers as parameters and returns their sum.

Replace the contents of anonymous.go with:

package main

import "fmt"

func main() {
    f := func(a, b int) int {
        return a + b
    }
    result := f(3, 5)
    fmt.Println(result)
}

Run the program:

go run anonymous.go

Expected output:

8

Now the anonymous function's signature is func(a, b int) int. This means it takes two integers (a and b) as input and returns an integer as output. The body of the function, return a + b, calculates and returns their sum. When we call f(3, 5), it executes the anonymous function with the arguments 3 and 5, and the result 8 is returned. We then store this result in the result variable and print it to the console.

Declaring and Calling Anonymous Functions Immediately

You can define and call an anonymous function all at once, without assigning it to a variable. This can be handy for quick, one-off operations.

Update anonymous.go:

package main

import "fmt"

func main() {
    res := func(a, b int) int {
        return a + b
    }(3, 5) // Call the anonymous function directly here
    fmt.Println(res)
}

Run the program:

go run anonymous.go

Expected output:

8

Here, we defined the anonymous function func(a, b int) int { return a + b } and immediately invoked it by adding (3, 5) after the function declaration. This syntax func(...) {...}(...) allows you to define and call a function in a single expression. The arguments inside the parenthesis are passed to the function right away. In this case, it returns the sum of 3 and 5, which is then assigned to the res variable. This is a common practice for simple, immediately-executed functions, and is useful for initialization or short calculations.

Using Anonymous Functions as Callback Functions

Anonymous functions can also be used as callbacks, which means we can pass them as arguments to other functions. This is useful when you want to customize the behavior of a function without creating a named function.

What are Callback Functions?

A callback function is a function that is passed as an argument to another function and is executed after the first function completes its task. This allows the caller to customize the behavior of the function being called, providing more flexibility and modularity. In essence, the function receiving a callback will call the callback function "back" at some point.

Why Use Anonymous Functions as Callbacks?

Anonymous functions work exceptionally well as callback functions because they often represent short, specific behaviors that are only used within a particular context. Using an anonymous function as a callback keeps the code more concise and avoids having to define a separate named function.

Replace anonymous.go with the following code:

package main

import (
    "fmt"
    "math"
)

// 'visit' takes a slice and a function. It applies the function to each element in the slice.
func visit(lst []float64, f func(float64)) {
    for _, value := range lst {
        f(value)
    }
}

func main() {
    arr := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}

    // Use an anonymous function to sum each element with itself
    visit(arr, func(v float64) {
        fmt.Printf("Sum:%.0f ", v+v)
    })
    fmt.Println()

    // Use an anonymous function to multiply each element by itself
    visit(arr, func(v float64) {
        fmt.Printf("Product:%.0f ", v*v)
    })
    fmt.Println()

    // Use an anonymous function to square each element using math.Pow
    visit(arr, func(v float64) {
        v = math.Pow(v, 2)
        fmt.Printf("Square:%.0f ", v)
    })
    fmt.Println()
}

Run the program:

go run anonymous.go

Expected output:

Sum:2 Sum:4 Sum:6 Sum:8 Sum:10 Sum:12 Sum:14 Sum:16 Sum:18
Product:1 Product:4 Product:9 Product:16 Product:25 Product:36 Product:49 Product:64 Product:81
Square:1 Square:4 Square:9 Square:16 Square:25 Square:36 Square:49 Square:64 Square:81

In this program, we first create a visit function that takes a slice (lst) of float64 and a function (f) of type func(float64). The visit function iterates over the slice and calls the provided function f for each element. This design pattern enables the visit function to execute different logic depending on the provided callback function f.

Inside the main function, we call visit three times with different anonymous functions to demonstrate how callbacks provide flexibility.

  • The first anonymous function calculates the sum of each element with itself.
  • The second anonymous function calculates the product of each element with itself.
  • The third anonymous function squares each element using math.Pow.

This illustrates how an anonymous function can be passed as a callback and how the visit function can perform different actions based on the callback function passed as a parameter. This makes your code more reusable and modular.

Summary

In this lab, you learned about anonymous functions in Go. Anonymous functions have no name and are often used for short, disposable pieces of logic. They can:

  • Be assigned to variables and called later.
  • Take parameters and return values.
  • Be defined and called immediately.
  • Serve as callbacks when passed as arguments to other functions, enabling highly flexible and customizable behavior.

Anonymous functions give you flexibility and convenience, especially when you need custom logic "on the fly" without cluttering your codebase with too many named functions. By using them effectively, you can create more expressive, concise, and modular Go programs. They're a powerful tool for writing cleaner, more readable, and more flexible code.