What is an anonymous function?
How to create an anonymous function.
How to call an anonymous function.
What is a closure?
What is a function type?
Anonymous function
Function literal
Lexical context
Scope
An anonymous function is similar to a traditional function except that the programmers did not give that function a name.
\nTo create an anonymous function, we use a function literal :
\n// anonymous/anon/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n // an anonymous function\n func() {\n // the instructions of the anonymous function\n fmt.Println("I am anonymous function")\n }()\n}
\nHere we define a function with no name by using the syntax func(){..}
and we execute it by adding the two parenthesis ()
.
So to define an anonymous function and execute it just after, you can use the following syntax :
\nfunc(){...}()
\nTo define the function, use the syntax : func(){..}
To define and run it : func(){..}()
Let’s take another example
\n// anonymous/example-2/main.go\npackage main\n\nimport (\n "fmt"\n "reflect"\n)\n\nfunc main() {\n\n /**\n * func literal not executed\n */\n myFunc := func() int {\n fmt.Println("I am a func litteral")\n return 42\n }\n // Output : nothing\n // the function is not executed\n\n fmt.Println(reflect.TypeOf(myFunc))\n // Output : func() int\n\n /**\n * func literal invoked\n */\n funcValue := func() int {\n fmt.Println("I am a func literal invoked")\n return 42\n\n }()\n // Output: I am a func literal invoked\n // the func is executed!\n fmt.Println(reflect.TypeOf(funcValue))\n // Output : int\n\n}
\nWhat is the most important thing here? Just remember that a function can have no name; you can store a function (not its result) but the function itself into a variable. This last thing causes a lot of trouble to many developers. We are confused because we are used to storing values and not functions inside variables!
\n\nYou can define a type based on a function signature. Here is an example taken from the gin module (https://github.com/gin-gonic/gin)
\npackage gin\n\n//...\n\ntype HandlerFunc func(*Context)\n\n//...
\nAnd here is an example taken from the standard http package :
\npackage http\n// ...\ntype HandlerFunc func(ResponseWriter, *Request)\n\n//...
\nA function type designates all functions with the same parameters and results.1. Once you have defined your type, you can create a variable that has a function type. Let’s take an example :
\ntype Funky func(string)\n\nvar f Funky\nf = func(s string){\n // my function defined\n log.Printf("Funky %s",s)\n}\nf("Groovy")
\nFunky
.Funky
designate all functions with a single string parameter and no results. (func(string)
)
We create a variable f
of type Funky
.
Then we assign to the variable f
an anonymous function
And then, we execute f
with f(\"Groovy\")
In some programming languages2 functions are “first-class citizens”3 allowing them to be :
\nUsed a parameters
Used as results
Assigned to a variable
Go functions are considered as first-class objects. It means that :
\nFunctions can be passed as arguments to other functions
You can return functions from other functions
You can bind functions to variables
An anonymous function defined into another function F
can use elements that are not defined in its scope but in the scope of F
.
Anonymous functions can keep references to its surrounding state. A closure is formed when a function references variables not defined in its own scope.4
\n\nHere is an example of a closure :
\n// anonymous/first-closure/main.go\npackage main\n\nimport "fmt"\n\nfunc printer() func() {\n k := 1\n return func() {\n fmt.Printf("Print n. %d\\n", k)\n k++\n }\n}\n\nfunc main() {\n\n p := printer()\n p()\n // Print n. 1\n p()\n // Print n. 2\n p()\n // Print n. 3\n}
\nWe have a function that is called printer
. The signature of this function is printer() func()
. This means that this function will return itself a function. func()
means that we return a function that returns nothing. We could have the following syntax as return type : func() int
this would mean that our returned function will return itself an integer. Let’s jump into the declaration of the function printer
. First, we define the variable k
which is initialized with the value 1. And then we return an anonymous function. Into this function, we use fmt.Printf
. to display into the standard output \"Print n. %d\\n\"
where %d
is replaced by the value of k
.
Here we :
\ndefine the variable k
in the outer function
we return a new anonymous function that makes use of k
.
Hence we have created a closure.
\nThen in the main function, we will assign to p
the return value of printer (which is a function). After that, we will use p
.
Remember that p
is a function, so to execute it, we have just to add parenthesis at the end :
p() // we execute p, the closure
\nThe type of p is func()
.
We say that this anonymous function captures it’s lexical context.
The function keeps a memory of the variables that are used in its environment.
The scope of a function (or lexical environment) is a region where you can use all the variables (types, constants) that you have declared in it.
The enclosing function defines an outer scope. In our case, we define the variable k
in the outer scope of the enclosing function. k
is then used in the returned function scope (the inner scope).
We use a variable in the inner scope that we declared in the outer scope.
The closures stores a reference to the variable that we defined in the outer scope.
That’s why when we execute our closure several time the value k
is incremented. The closure holds the reference, and each time we execute it, it will modify the underlying value.
You can pass a function as a parameter of another function. In the sort package (part of the standard library), several functions accept functions as parameters :
\n// sort package\n\n// Search for an index of a specific value using binary search\nfunc Search(n int, f func(int) bool) int\n\n// sort a slice by using the provided function (less)\nfunc Slice(slice interface{}, less func(i, j int) bool)
\nIn the two previous signature, we see that sort.Search
and sort.Slice
functions are requiring both a function to work. The function is used internally to do the sorting job.
Let’s take an example :
\n// anonymous/input-parameters/main.go\npackage main\n\nimport (\n "fmt"\n "sort"\n)\n\nfunc main() {\n scores := []int{10, 89, 76, 3, 20, 12}\n // ascending\n sort.Slice(scores, func(i, j int) bool { return scores[i] < scores[j] })\n fmt.Println(scores)\n // Output : [3 10 12 20 76 89]\n\n // descending\n sort.Slice(scores, func(i, j int) bool { return scores[i] > scores[j] })\n fmt.Println(scores)\n // Output : [89 76 20 12 10 3]\n}
\nWe define a variable scores
, which is a slice of integers. They represent the winning score for 6 “gophing” games (a new sport practiced only by gophers).
The scores
are not sorted at all. The objective is to sort them following an order.
We will use the function sort.Slice
.
Its signature requires a slice and a function. The function will define how the runtime will execute the sort. The functions take two parameters (integers); they represent two indexes. It returns a boolean.
We have here a closure because the function uses the variable scores
, even if it is not defined in its inner scope.
In our first example, the less function is :
\nfunc(i, j int) bool { return scores[i] < scores[j] }
\nThe element at index i
will be placed before the element at index j
if the element at index i
is less than the element at index j
.
As a result, our slice will be sorted in ascending order :
\n[3 10 12 20 76 89]
\nIn the second call to sort.Slice
we are giving as input the following function :
func(i, j int) bool { return scores[i] > scores[j] }
\nThe element at index i
will be placed before the element at index j
if the element at index i
is greater than the element at index j
. The result is a descending ordered slice :
[89 76 20 12 10 3]
\n\nWe can use closures to wrap other functions.
\nBefore explaining the technique, we will build a simple web server (you can skip the paragraph if you already know how to do it)
\n\nIn the following code block, we are specifying that when a request is sent to the endpoint \"/homepage\"
the function homepageHandler
will be executed.
// anonymous/wrappers/main.go \n\nfunc homepageHandler(writer http.ResponseWriter, request *http.Request) {\n fmt.Fprintln(writer, "Welcome to my homepage")\n fmt.Fprintln(writer, "I am max")\n}
\nThe homepageHandler
function takes a response writer (http.ResponseWriter
) (to prepare the response) and the request (*http.Request
).
Here is a minimal web server example :
\n// anonymous/wrappers/main.go \n\npackage main\n\nimport (\n "fmt"\n "net/http"\n)\n\nfunc main() {\n http.HandleFunc("/homepage", homepageHandler)\n err := http.ListenAndServe(":3000", nil)\n if err != nil {\n log.Fatal(err)\n }\n\n}\nfunc homepageHandler(writer http.ResponseWriter, request *http.Request) {\n fmt.Fprintln(writer, "Welcome to my homepage")\n fmt.Fprintln(writer, "I am max")\n\n}
\n\nImagine that your web server has several endpoints. and you want to keep track of visits on each endpoint.
\nThe brutal way to do this would be to add a counter in each of your handlers.
\nBut there is a clever way: you can create a generic wrapper that all your handlers can use. Your wrapper should take as input a handler and return a handler. That way, you can have the following syntax :
\nhttp.HandleFunc("/homepage", trackVisits(homepageHandler))
\nThis is elegant! We understand that here we track the visits and then we execute the handler. Let’s implement the trackVisits
function :
func trackVisits(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {\n return func(writer http.ResponseWriter, request *http.Request) {\n // track the visit\n fmt.Println("one visit !")\n // call the original handler\n handler(writer, request)\n }\n}
\nThe trackVisits
function takes a handler
as parameter and returns a handler
.
The return type of trackVisits
must have the same signature as the one expected by the second input parameter of http.HandleFunc
.
In the function body, we are returning an anonymous function. This anonymous function will first print that we have one visit and then launch the original handler’s execution.
This technique is very powerful. It gives us the power to create generic wrappers that we can use on several endpoints: it avoids code duplication.
\nhttp.HandleFunc("/homepage", trackVisits(homepageHandler))\nhttp.HandleFunc("/cv", trackVisits(cvHandler))\nhttp.HandleFunc("/projects", trackVisits(projectsHandler))
\nIs it also possible to chain the wrappers :
\nhttp.HandleFunc("/projects", authenticate(trackVisits(projectsHandler)))
\nby defining other wrappers :
\nfunc authenticate(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {\n return func(writer http.ResponseWriter, request *http.Request) {\n // check that request is authenticated\n fmt.Println("authenticated !")\n // call the original handler\n handler(writer, request)\n }\n}
\n\nDave Cheney has described this pattern5. It is a pattern that allows you to improve the API of your libraries.
\nUsually, a library offers several “options”. With this pattern, options are provided with functions.
\n\nLet’s take an example of a fake authentication library :
\nauth := authenticator.New("test", authenticator.UnverifiedEmailAllowed(), authenticator.WithCustomJwtDuration(time.Second))\n\nif auth.IsValidJWT("invalid") {\n log.Println("mmmm... maybe we should use another lib.")\n}
\nWe call authenticator.New
to initialize a new authenticator
We pass to the function a string \"test\"
and two other parameters, which are
authenticator.UnverifiedEmailAllowed()\n\nauthenticator.WithCustomJwtDuration(time.Second)
Those two additional parameters are function calls that will return a value.
You see here that options are set with functions.
\n\n// anonymous/functionalOptions/authenticator/authenticator.go \npackage authenticator\n\nimport (\n "time"\n)\n\ntype options struct {\n jwtDuration time.Duration\n allowUnverifiedEmail bool\n allowUnverifiedPhone bool\n}\n\ntype Option func(*options)\n\nfunc WithCustomJwtDuration(duration time.Duration) Option {\n return func(options *options) {\n options.jwtDuration = duration\n }\n}\n\nfunc UnverifiedEmailAllowed() Option {\n return func(options *options) {\n options.allowUnverifiedEmail = true\n }\n}\n\nfunc UnverifiedPhoneAllowed() Option {\n return func(options *options) {\n options.allowUnverifiedEmail = true\n }\n}\n\ntype Authenticator struct {\n name string\n options options\n}\n\nfunc New(name string, opts ...Option) *Authenticator {\n options := options{\n jwtDuration: time.Hour,\n }\n for _, opt := range opts {\n opt(&options)\n }\n return &Authenticator{name: name, options: options}\n}\n\nfunc (a Authenticator) IsValidJWT(jwt string) bool {\n return false\n}
\nFirst an options
struct is created
This struct will keep track of the options set.
Each option is a field (unexported).
A function type is created type Option func(*options)
For each option, we create an exported function that will return an Option
func UnverifiedEmailAllowed() Option {\n return func(options *options) {\n options.allowUnverifiedEmail = true\n }\n}
New
will take as second parameter Option
s
This function is variadic, because it can be invoked with zero or more arguments of type Option
.
Inside New
:
First, the default values are set.
Then we iterate over opts
(which is a slice of Option
)
At each iteration, we get a function that set an option
We simply execute the function with opt(&options)
True or False? You cannot assign an anonymous function to a variable.
True or False? You cannot define a named function inside a function
True or False? You cannot define an anonymous function inside a function
Fill in the blank : “An ______ can be declared with a type ____.”
Can an anonymous function use a variable not defined in its body or parameter list?
True or False? You cannot assign an anonymous function to a variable.
\nFalse
You can assign an anonymous function to a variable
f35 := func()uint{ return 35}
True or False? You cannot define a named function inside a function
\nThis is true
The following snippets won’t compile :
func main(){\n func insideFunction(){\n\n }\n}\n\nfunc main(){\n f := func(s string){\n func insideFunction(){\n\n }\n test()\n }\n}
True or False ? You cannot define an anonymous function inside a function
\nFill in the blank : “An ______ can be declared with a type ____.”
\nName one common use case of closures.
\nCan an anonymous function use a variable not defined in it’s body or parameter list?
\nYes
An anonymous function can use elements defined in its enclosing function.
To define an anonymous function, use a function literal
\nfunc(){ fmt.Println("my anonymous function")}
A function literal can be assigned to a variable
\nmyFunc := func(){ fmt.Println("my anonymous function")}
To define & immediately call an anonymous function use parenthesis :
\nfunc(){ fmt.Println("my anonymous function")}()
\nA function type designate all functions with the same parameters and results
\nThe zero value of the function type is nil
Ex :
\ntype Option func(*options)
Functions are “first-class citizen”.
\nThey can be passed as parameter
They can be returned as result
They can be assigned to a variable
An anonymous function can use elements (variables, types, constants) that are defined in its surrounding scope
\nhttps://golang.org/ref/spec#Function_types↩︎
Especially functional languages↩︎
This term was introduced indirectly in 1967 by CHRISTOPHER STRACHEY, see
See : https://en.wikipedia.org/wiki/Closure_(computer_programming)#Lexical_environment, https://tour.golang.org/moretypes/25↩︎
See: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis and https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions↩︎
Previous
\n\t\t\t\t\t\t\t\t\tErrors
\n\t\t\t\t\t\t\t\tNext
\n\t\t\t\t\t\t\t\t\tJSON and XML
\n\t\t\t\t\t\t\t\t