In this article, you will learn how to work with closure functions in Go programming with the help of practical examples.
In Golang, a closure is a function that references variables outside of its body/scope. Thus its function can access variables within that scope and assign them to the referenced variable, even after the scope is destroyed.
Go supports anonymous functions, which creates a basic foundation of closures. They are essential when you want to define a function inline without having to name it. You can learn more about anonymous function from our previous article anonymous functions in Go
What is a closure function in Go?
In Golang, the closure function is an anonymous nested function that has access to variables defined outside the body/scope of the closure. A closures function in Go can hold a unique state of its own. The state becomes isolated as we create new instances of the function.
Example on how to create closure function in Go
package main
import (
"fmt"
"os"
)
// func()string{} îs closure function returned from displayMessage()
// outer function
func displayMessage(msg string) func() string {
// return a nested anonymous function
return func() string {
msg = "Hello from " + msg
return msg
}
}
func main() {
// call the outer function
inputString := os.Args[1]
resultMessage := displayMessage(inputString)
// call the inner function
fmt.Println(resultMessage())
}
Explanation:-
func displayMessage(msg string) func() string {}
:- displayMessage function accepts name inputs as string. It returns a closure function which displays a concatenated string with the passed inputs.
inputString := os.Args[1]
:- we are using OS
package to read users inputs using Args[] function and store the value as inputString variable, then pass it to our displayMessage()
function.
resultMessage := displayMessage(inputString)
:- resultMessage is a variable that holds the results from the displayMessage function which return a function closure. closure function can access all variables defined outside the scope. For instance, the msg string
passed from the displayMessage()
function which upon execution, the input string is concatenated, and its state is isolated or destroyed when a new instance of the function is created. Through the closure function, we can still access the msg string concatenated.
return func() string {
msg = "Hello from " + msg
return msg
}
fmt.Println(resultMessage())
we call an inner function which displays the message.
Output:-
$ go run closure.go GoLinuxCloud
Hello from GoLinuxCloud
Uses of closure function in Golang
In Golang, we use closure function in various ways:-
- Wrapping function in a Go server
- Binary search in Go
- Creating Middleware in Go
Wrapping function in a Go server
In Go, net/http
package, provides ListenAndServer()
and handleFunc()
function which enables easy use of closure function in creating web server i.e http.ListenAndServe(":5000", nil)
and defining the web routes. i.e http.HandleFunc("/msg", send Message)
example of sendMessage route. Closure enables wrapping this handler functions with the application business logic.
Example of closure wrapping functions in web server in Go
package main
import (
"net/http"
)
func main() {
//routes
http.HandleFunc("/message", sendMessage)
//listen to server and traffics
http.ListenAndServe(":8080", nil)
}
// This function is wrapped in http.HandleFunc() function using closure to call the route that matches.
func sendMessage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
msg:= "Hello GoLinuxCloud"
w.Write([]byte(msg))
}
Output:-
$ curl localhost:8080/message
Hello GoLinuxCloud
Binary search in Go
We use go closure in binary search through go sort
package which provide us with sort.Search()
function used in binary search. It expects a closure function that returns a boolean result for a position of the element being searched. the closure returns false if the index of the element passed into the array is not found and true if the element is found within the array and its position is known.
Example of closure function in Binary Search in Go
We have to provide you with an array of integers and allow the user to pass any arguments of choice. search the passed element within the array and return its position.
package main
import (
"fmt"
"os"
"sort"
"strconv"
)
func main() {
fmt.Println("Enter any number between 1 and 15 \n")
input, _ := strconv.Atoi(os.Args[1])
arrayInt := []int{5, 4, 1, 12, 8, 2, 7, 25, 11, 13, 14, 9, 10, 6, 3}
sort.Ints(arrayInt)
// The closure function func()bool{} is capable of reading the element passed position in a sorted array in ascending order.
// It helps in getting the position of element user entered.
elementSearch := sort.Search(len(arrayInt), func(i int) bool {
return arrayInt[i] >= input
})
fmt.Println(elementSearch)
if elementSearch < len(arrayInt) && arrayInt[elementSearch] == input {
fmt.Printf("This integer %d you provide is situated at index %d in our array of integers %v\n", input, elementSearch, arrayInt)
} else {
fmt.Printf("This integer %d you have provided does not exist in our array of integers %v\n", input, arrayInt)
}
}
Output
Element outside the array scope:
$ go run closure.go 17
Enter any number between 1 and 15
This integer 17 you have provided does not exist in our array of integers [1 2 3 4 5 6 7 8 9 10 11 12 13 14 25]
Element within the array scope
$ go run closure.go 14
Enter any number between 1 and 15
This integer 14 you provide is situated at index 13 in our array of integers [1 2 3 4 5 6 7 8 9 10 11 12 13 14 25]
Summary
In the article, we have covered An anonymous function and a Closure function. The anonymous function is a function without a name and in Go, functions can return other functions. For instance, by returning an anonymous function or passing parameters into an anonymous function. A closure function is a function value that references variables outside its own function body(scope). A closure is able to outlive the scope of the function in which it is defined. Thus closure function can access the out-scoped variables or in the global scope.
Reference