A function is just another type — just like int
and string
and bool
. 1
Table of contents
a function as a parameter
a full code snippet
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func mul(x, y int) int {
return x * y
}
// aggregate applies the given math function to the first 3 inputs
func aggregate(a, b, c int, arithmetic func(int, int) int) int {
return arithmetic(arithmetic(a, b), c)
}
func main() {
fmt.Println(aggregate(2, 3, 4, add)) // prints 9
fmt.Println(aggregate(2, 3, 4, mul)) // prints 24
fmt.Println("vim-go")
}
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func mul(x, y int) int {
return x * y
}
// aggregate applies the given math function to the first 3 inputs
func aggregate(a, b, c int, arithmetic func(int, int) int) int {
return arithmetic(arithmetic(a, b), c)
}
func main() {
fmt.Println(aggregate(2, 3, 4, add)) // prints 9
fmt.Println(aggregate(2, 3, 4, mul)) // prints 24
fmt.Println("vim-go")
}
currying
Function currying is the practice of writing a function that takes a function (or functions) as input, and returns a new function.
a full code snippet
package main
import "fmt"
func main() {
squareFunc := selfMath(multiply)
doubleFunc := selfMath(add)
fmt.Println(squareFunc(5)) // prints 25
fmt.Println(doubleFunc(5)) // prints 10
}
func multiply(x, y int) int {
return x * y
}
func add(x, y int) int {
return x + y
}
func selfMath(mathFunc func(int, int) int) func(int) int {
return func(x int) int {
return mathFunc(x, x)
}
}
closures
A closure is a function that references variables from outside its body. The function may access and assign to the referenced variables.
a full code snippet
package main
import "fmt"
func concatter() func(string) string {
doc := ""
return func(word string) string {
doc += word + " "
return doc
}
}
func main() {
makeHarryPotter := concatter()
makeHarryPotter("Mr.")
makeHarryPotter("and")
makeHarryPotter("Mrs.")
makeHarryPotter("Dursley")
makeHarryPotter("of")
makeHarryPotter("number")
makeHarryPotter("four,")
makeHarryPotter("Privet")
fmt.Println(makeHarryPotter("Drive"))
// prints Mr. and Mrs. Dursley of number four, Privet Drive
}
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(num int) int {
sum += num
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
"You've sent",
pos(i),
"emails and it has cost you",
neg(3*i),
"cents.",
)
}
}
/**
OUTPUT
You've sent 0 emails and it has cost you 0 cents.
You've sent 1 emails and it has cost you 3 cents.
You've sent 3 emails and it has cost you 9 cents.
You've sent 6 emails and it has cost you 18 cents.
You've sent 10 emails and it has cost you 30 cents.
You've sent 15 emails and it has cost you 45 cents.
You've sent 21 emails and it has cost you 63 cents.
You've sent 28 emails and it has cost you 84 cents.
You've sent 36 emails and it has cost you 108 cents.
You've sent 45 emails and it has cost you 135 cents.
*/
anonymous functions
Anonymous functions are useful when defining a function that will only be used once or to create a quick closure.
a full code snippet
package main
import "fmt"
// doMath accepts a function that converts one int into another
// and a slice of ints. It returns a slice of ints that have been
// converted by the passed in function.
func doMath(f func(int) int, nums []int) []int {
var results []int
for _, n := range nums {
results = append(results, f(n))
}
return results
}
func main() {
nums := []int{1, 2, 3, 4, 5}
// Here we define an anonymous function that doubles an int
// and pass it to doMath
allNumsDoubled := doMath(func(x int) int {
return x + x
}, nums)
fmt.Println(allNumsDoubled) // prints: [2 4 6 8 10]
}
variadic functions
Variadic functions allow to pass an arbitrary number of arguments to a function, making your code more flexible and efficient.2 A variadic function has the ...
operator followed by the type of arguments.
a full code snippet
A variadic function is a function that can accept an arbitrary number of arguments. In Go, you can define a variadic function by using the ...
operator followed by the type of the arguments. Let’s take a look at an example:
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
In the above code, sum
is a variadic function that accepts any number of integers. Within the function, the type of nums
is equivalent to []int
, which means we can call len(nums)
, iterate over it with range
, and perform any other operations that we can do on a slice.
calling variadic functions
sum(1, 2)
sum(1, 2, 3)
nums := []int{1, 2, 3, 4}
sum(nums...)
variadic functions with other parameters
Variadic functions can also have other parameters. The variadic parameter must be the last parameter in the function signature. Here’s an example:
func printNumbers(sep string, nums ...int) {
for i, num := range nums {
if i > 0 {
fmt.Print(sep)
}
fmt.Print(num)
}
fmt.Println()
}
printNumbers(", ", 1, 2, 3) // prints "1, 2, 3"