Functional Programming in Go: Capabilities and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Functional Programming in Go: From Theory to Practice



Go (Golang) was not originally designed as a purely functional language. However, its powerful type system, support for first-class functions, and closures allow you to successfully apply the principles of functional programming (FP). In this article, we will explore how to use a functional style in Go to write more predictable, testable, and concurrency-safe code.



1. First-Class Functions and Higher-Order Functions



In Go, functions are first-class objects. This means they can be assigned to variables, passed as arguments, and returned from other functions. Functions that work with other functions are called higher-order functions.



Example: passing a function as an argument



package main

import "fmt"

// Higher-order function: takes a function and applies it to a numberfunc applyOperation(x int, op func(int) int) int { return op(x)}

func double(x int) int { return x * 2}

func square(x int) int { return x * x}

func main() { result1 := applyOperation(5, double) result2 := applyOperation(5, square)

fmt.Println("Double:", result1) // 10 fmt.Println("Square:", result2) // 25}


Example: returning a function from a function (function factory)



package main

import "fmt"

// Returns a function that adds a given valuefunc createAdder(x int) func(int) int { return func(y int) int { return x + y }}

func main() { addFive := createAdder(5) addTen := createAdder(10)

fmt.Println(addFive(3)) // 8 fmt.Println(addTen(3)) // 13}


2. Closures in Go



A closure is a function that "remembers" variables from its outer scope, even after that scope has finished executing. Closures are a powerful tool for creating encapsulated state and function factories.



Example: sequence generator



package main

import "fmt"

func sequenceGenerator() func() int { i := 0 return func() int { i++ return i }}

func main() { next := sequenceGenerator()

fmt.Println(next()) // 1 fmt.Println(next()) // 2 fmt.Println(next()) // 3

// New generator starts from 1 next2 := sequenceGenerator() fmt.Println(next2()) // 1}


Important: Be careful with closures in loops. In older versions of Go (before 1.22), the loop variable i was reused, which led to errors. Starting from Go 1.22, loop variables are captured by value.



3. Pure Functions and Immutability



A pure function is a function that:

  • Always returns the same result for the same arguments.
  • Has no side effects (does not modify external state, does not write to files/network).

Go does not have built-in support for immutability, but we can follow this principle ourselves.



Example: pure vs impure function



package main

import "fmt"

// IMPURE function: modifies an external slicevar counter int

func impureAddToSlice(s []int, val int) []int { counter++ // side effect return append(s, val)}

// PURE function: creates a new slicefunc pureAddToSlice(s []int, val int) []int { newSlice := make([]int, len(s)+1) copy(newSlice, s) newSlice[len(s)] = val return newSlice}

func main() { original := []int{1, 2, 3}

// Pure approach result := pureAddToSlice(original, 4) fmt.Println("Original:", original) // [1 2 3] - unchanged fmt.Println("Result:", result) // [1 2 3 4]}


Tip: For working with immutable struct

Blogs

Book Recommendations