Functions are essential in any programming language. They help structure the code and make routine tasks easier to do. Go has support for “First Class Functions” which means functions in Go can be assigned to variables, passed as an argument and can be returned from another function.
Declaring and calling functions
To declare a function we use the func keyword. The general structure of a function declaration is shown below.
func nameOfFunction(arguments) (returnTypes) {
// body
}
Let’s write a function that prints “Hello World!” in the console.
package main
import (
"fmt"
)
func main() {
helloWorld() // call function
}
func helloWorld() { // declare the function
fmt.Println("Hello World!") // prints "Hello World!"
}
As you can see, calling a function is really easy.
Return types and arguments
Functions in Go can have any return type and any type of argument. Let’s see how to declare those.
package main
import (
"fmt"
)
func main() {
greetUser("John") // prints "Hello, John"
fmt.Println(add10(12)) // prints 22
}
func greetUser(user string) {
fmt.Printf("Hello, %s\n", user)
}
func add10(value int) int {
return value + 10
}
In the code above the greetUser() function has no return type declared. But an argument of type string is given. In function add10() the parameter is of type int and the return type is also int.
Multiple arguments in a Function
Multiple arguments can be passed inside a function. We will see an example of how to do that.
package main
import (
"fmt"
)
func main() {
showAge("Paul", 22) // prints "Paul is 22 years old."
fmt.Println(multiplyTwoNumbers(12, 23)) // prints 276
}
func showAge(name string, age int) {
fmt.Printf("%s is %d years old.\n", name, age)
}
func multiplyTwoNumbers(x, y int) int { // same type of arguments
return x*y
}
Go Function with multiple return values
A function can return as many values as you want. Here is an example illustrating how to do that.
package main
import (
"fmt"
)
func main() {
vAdd, vSub := addSub(35, 25)
fmt.Printf("35 + 25 = %d\n", vAdd) // prints "35 + 25 = 60"
fmt.Printf("35 - 25 = %d\n", vSub) // prints "35 - 25 = 10"
}
func addSub(x, y int) (int, int) { // multiple return values (int, int)
return x+y, x-y
}
Named return values in Go
Function return values can be named in Golang. It allows mentioning the names of the variables and so Here is an example doing just that.
package main
import (
"fmt"
)
func main() {
fmt.Println(divby10(100))
}
func divby10(num int) (res int) {
res = num/10
return res
}
Go Functions as call by “value” and “reference”
In Go, a function can take a parameter by value or reference. Let’s see what happens when it takes value.
package main
import (
"fmt"
)
func main() {
val := 12
fmt.Printf("The value before function call is %d\n", val)
changeValue(val) // does not change value
changeValueByRef(&val) //changes value
fmt.Printf("The value after function call is %d\n", val)
}
func changeValue(num int) {
num = 42
}
func changeValueByRef(num *int) {
*num = 42
}
In the above code, the function when it takes value does not change it at all. But, when it takes reference it changes the value.
Returning an error from the function
A function can return an error. Errors are a way to show that unexpected thing happened. So, it is necessary to have it.
Using the blank identifier
The blank identifier is used because Go gives a warning when a variable is declared but never used. The syntax is to use “_” to assign the value.
package main
import (
"fmt"
)
func main() {
j, _ := returnTwoNumbers() // ignores the second return value
fmt.Println(j)
}
func returnTwoNumbers() (int, int) {
return 12, 23
}
Anonymous functions
Since Go supports First Class Functions, that means you can assign a function to a variable or even invoke it immediately. Below is an example code.
package main
import (
"fmt"
)
func main() {
getMod := func(a, b int) (int) { // declare it
return a%b
}
fmt.Println(getMod(12, 5)) // prints 2
// call by its name
}
Immediate invocation of a function
In the below code an anonymous function is immediately invoked.
package main
import (
"fmt"
)
func main() {
func(name string) {
fmt.Printf("Hello, %s", name)
}("John") // prints "Hello, John"
}
The “defer” keyword
“Defer” is a keyword to delay function call till surrounding function returns.
package main
import "fmt"
func main() {
defer fmt.Println("before this.") // runs at the end
fmt.Println("This is printed ") // runs first
}
User-defined function types
User-defined function types are types that can be identified as a function. Below is an example.
package main
import (
"fmt"
)
type First func(int) int // declare type
func getFunction() First { // use it
return func(val int) int {
return val * 5
}
}
func main() {
f := getFunction() // returns a function of type First
fmt.Println(f(12))
}
Functions as arguments
Functions in Go can be passed as arguments. This allows us to create Higher Order Functions.
Returning functions from function
A function can return another function as well. Here is how to do that.
package main
import (
"fmt"
)
func main() {
f := getFunction("John") // returns a function
f() // prints "Hello, John"
}
func getFunction(name string) func() {
return func() {
fmt.Printf("Hello, %s", name)
}
}
Function closures
Function closures are an important concept to understand. As it will help create better code and increase your understanding of the language. So, what is a closure? A closure is a function that is bound to the variables in its scope. That means each closure has its own scope.