Functions in GoLang

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.