SoFunction
Updated on 2025-03-04

Golang functional programming in-depth analysis example

Define collection function functions

First define the structure used for testingWorkWith

// WorkWith is the struct we'll
// be implementing collections for
type WorkWith struct {
	Data    string
	Version int
}

Define filter and map functions for this structure:

// Filter the set based on the judgment function and return the set elements that meet the conditionsfunc Filter(ws []WorkWith, f func(w WorkWith) bool) []WorkWith {
	// depending on results, smaller size for result
	// is len == 0
	result := make([]WorkWith, 0)
	for _, w := range ws {
		if f(w) {
			result = append(result, w)
		}
	}
	return result
}
// Convert the set element based on the conversion function, and return the element of the set as the converted elementfunc Map(ws []WorkWith, f func(w WorkWith) WorkWith) []WorkWith {
	// the result should always be the same
	// length
	result := make([]WorkWith, len(ws))
	for pos, w := range ws {
		newW := f(w)
		result[pos] = newW
	}
	return result
}

Implement specific function functions

import "strings"
// LowerCaseData does a ToLower to the
// Data string of a WorkWith
func LowerCaseData(w WorkWith) WorkWith {
	 = ()
	return w
}
// IncrementVersion increments a WorkWiths
// Version
func IncrementVersion(w WorkWith) WorkWith {
	++
	return w
}
// OldVersion returns a closures
// that validates the version is greater than
// the specified amount
func OldVersion(v int) func(w WorkWith) bool {
	return func(w WorkWith) bool {
		return  >= v
	}
}

There are three functions defined above. LowerCaseData modify the Data value in WorkWith to lowercase, IncrementVersion increases the version in WorkWith by 1, and OldVersion filters the version based on parameters.

Test collection function

Define test case files:

import (
	"fmt"
	"testing"
)
func TestMap(t *) {
	ws := []WorkWith{
		{"Example", 1},
		{"Example 2", 2},
	}
	("Initial list: %#v\n", ws)
	// first lower case the list
	ws = Map(ws, LowerCaseData)
	("After LowerCaseData Map: %#v\n", ws)
	// next increment all versions
	ws = Map(ws, IncrementVersion)
	("After IncrementVersion Map: %#v\n", ws)
	// lastly remove all versions older than 3
	ws = Filter(ws, OldVersion(3))
	("After OldVersion Filter: %#v\n", ws)
}

Run go test . -v

The output result is as follows:

Initial list: []{{Data:"Example", Version:1}, {Data:"Example 2", Version:2}}

After LowerCaseData Map: []{{Data:"example", Version:1}, {Data:"example 2", Version:2}}

After IncrementVersion Map: []{{Data:"example", Version:2}, {Data:"example 2", Version:3}}

After OldVersion Filter: []{{Data:"example 2", Version:3}}

In the above example, we noticed that none of the functions returns any error objects, which follows the idea of ​​functional programming, making the function as pure as possible: do not modify the original set elements, that is, there are no side effects on the original set, but generate a new set. If multiple functions are required to apply to the collection, this pattern can save a lot of trouble and test it is also simple. We can also link maps and filters together to make the code more concise and readable.

	ws := []WorkWith{
		{"Example", 1},
		{"Example 2", 2},
	}
	("Initial list: %#v\n", ws)
	result := Filter(Map(Map(ws, LowerCaseData), IncrementVersion), OldVersion(3))
	("After OldVersion Filter: %#v\n", result)

If the function function is defined as a method of the collection type and returns the collection type, the above code will be more elegant.

Generic implementation

The above code can only be used on specific types. We naturally want to implement generic functions. The following is a simple example:

func map2[T, U any](data []T, f func(T) U) []U {
    res := make([]U, 0, len(data))
    for _, e := range data {
        res = append(res, f(e))
    }
    return res
}

This function receives type T and returns type U after conversion. Of course, both types can be the same. The following test function function:

    // String to uppercase    words := []string{"war", "cup", "water", "tree", "storm"}
    result := map2(words, func(s string) string {
        return (s)
    })
    (result)
    // Generate a squared set of original collection elements    ("-------------------")
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    squares := map2(numbers, func(n int) int {
        return n * n
    })
    (squares)
    // Convert the value to a string    ("-------------------")
    as_strings := map2(numbers, func(n int) string {
        return (n)
    })
    ("%q", as_strings)

This is the end of this article about Golang's in-depth analysis of examples of Go functional programming. For more related Go functional programming content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!