LanguagesUnderstanding Functions in Go

Understanding Functions in Go

Functions are the building blocks of procedural programming. They help in creating modular code where a big job can be segmented into small pieces of code and might have been written by different people separated by both time and space. They also help in hiding implementation details from users. For practical reasons, functions are a critical part of any programming language. Here we’ll provide an introduction to the overall concept of function and its implementation in Go, along with coding examples.

The init function

The function main() and init() are the two special purpose functions reserved to be used by the Go compiler. Both these functions do not take any argument nor do they return any value. The init() function is declared implicitly and we cannot reference it from anywhere in the code, but we are allowed to create multiple init() functions in the same program. In such a case the order of execution of multiple init() functions will be in the order they are created. If multiple init() functions are created in multiple files, then their execution order will be according to the lexical order of the file name. The main purpose of the init() function is initialization of global variables prior to the invocation of the main() function.

The main function

Every piece of Go code is written inside a main package and the package that begins a Go program has a function called main().This function is the entry point of Go program execution. This means that this is the first function that executes (apart from init() function). As mentioned earlier, the main() function does not take any argument nor return a value. Unlike init() it does not make sense to write multiple main() functions in a Go program and hence is not allowed.

Custom function

There is more than one reason why we need to create modular code and that is why functions are important both from the point of view of procedural programming as well object-oriented programming. Go provides excellent support for creating custom functions according to need. The syntactical structure of a function declaration is pretty simple.

Function declaration

According to Go syntax function, declaration begins with the keyword – func. The keyword then is followed by a name called function-name. The rules for naming a function is that it must not begin with a number or any other character except underscore (‘_’). Good programming practice is that a function name should meaningfully be consistent with the value it contributes. The idea is that the name should give the programmer a hint as to its purpose. Therefore, a name like _8TKK, though syntactically valid, does not give a proper hint to its purpose. A name such as _areaOfCircle gives a proper idea of what the function actually does. Also a function name such as _ADD is not the same as _add, Go is sensitive to the case of letters used in naming. The specific format of a Go function may be divided into five parts.


func function_name(list_of_parameters)(return_type) {
//...
//function_body
}

 

  1. func: A keyword in Go used specifically to create function
  2. function_name: The name given during creation and by which the function is known
  3. list_of_parameters: The parameters list refers to the number and type of arguments it takes. The parameters are passed to the function during function call. There can be zero or more parameters. If there are no parameters, the parentheses are left blank. More than one parameter in the parameter list is separated by a comma. The parentheses are compulsory in any case. Sometimes the last parameter is preceded by an ellipsis (…) to mean that the function will accept zero or more parameters of type []type. This type of function is called a variadic function.
  4. return_type: The value that the function may return to the caller after due processing. It is an optional part (including the parentheses) and may be omitted to mean that the function does not return anything. Unlike C and C++ a function in Go may return zero or more values. A function that has one or more return values must have at least one return statement or have a call to panic() as the last statement.
  5. function_body: The function body is the part where function logic is written. It is encompassed within the curly braces.

The example below demonstrates different types of functions such as zero or more arguments functions, zero or multiple returns, and variadic function calls from the main function.


package main

import (
	"fmt"
	"math"
	"strings"
)

func main() {

	simpleFunction()

	showSquareRoot(56)

	fmt.Printf("three numbers 11,22,33 added %d\n", addThreeNumbers(11, 22, 33))

	fmt.Printf("Area Of Circle is %f\n", areaOfCircle(5.23))

	fmt.Println("Variadic function call")
	fmt.Println("Sum = ", addNNumbers(1, 2))
	fmt.Println("Sum = ", addNNumbers(1, 2, 3))
	fmt.Println("Sum = ", addNNumbers(1, 2, 3, 4, 5))
	fmt.Println("------------------------------------")

	a, b := 10, 20
	fmt.Printf("Before swap: The value of a,b is %d, %d\n", a, b)
	a, b = swap(a, b)
	fmt.Printf("After swap: The value of a,b is %d, %d\n", a, b)

}

func simpleFunction() {
	fmt.Println("simple function")
}

func showSquareRoot(num float64) {
	fmt.Printf("The square root of %v is %v\n", num, math.Sqrt(num))
}

func addThreeNumbers(a, b, c int) int {
	return (a + b + c)
}

func swap(a, b int) (int, int) {
	c := a
	a = b
	b = c
	return a, b
}

func doSomething(a, b, c float64, name string) (float64, float64, string) {
	mul := a * b * c
	add := a + b + c
	upper := strings.ToUpper(name)
	return mul, add, upper
}

func addNNumbers(numbers ...int) int {
	sum := 0
	for _, n := range numbers {
		sum += n
	}
	return sum
}

func areaOfCircle(radius float64) float64 {
	area := math.Pi * math.Pow(radius, 2)
	return area
}

Output:


simple function
The square root of 56 is 7.483314773547883
three numbers 11,22,33 added 66
Area Of Circle is 85.931670
Variadic function call
Sum =  3
Sum =  6
Sum =  15
------------------------------------
Before swap: The value of a,b is 10, 20
After swap: The value of a,b is 20, 10

Closure function

In Go we can define a function within a function. This type of function is called a closure function. Closure functions are anonymous and have almost the same syntax as normal functions except that they have no name. This type of function is particularly useful in a situation where we do not want to create a separate function nor do we want a piece of code to be a part of an existing logic of a function. Closure functions have some specialized uses. A complete explanation would require a separate article. To supplement the rudimentary idea here is a trivial example on how closure functions may be written.


func main() {

	str1, str2, str3 := addFileExtension("MyFile")

	fmt.Printf("File Names: %s, %s, %s", str1, str2, str3)

}

func addFileExtension(fileName string) (string, string, string) {

	toDocx := func(file string) string { return file + ".docx" }
	toTex := func(file string) string { return file + ".tex" }
	toPdf := func(file string) string { return file + ".pdf" }

	return toDocx(fileName), toTex(fileName), toPdf(fileName)
}

Recursive function

A function that calls itself is called a recursive function, and functions that mutually call each other are called mutually recursive functions. The typical characteristic of a recursive function is that it must have an exit condition as it calls itself recursively. The purpose of the exit condition is to break the call and ensure that the function eventually stops at a certain point. Other than that, recursive functions are like normal functions. Any logic that can be defined recursively can also be defined in a non-recursive fashion. But the point of a recursive function is that some data structures or algorithms such as binary trees or numerical computations are best expressed through recursive function. An example:


For example the recursive function for n-th number Fibonacci series can be written in Go as follows:

func fibonacci(num int) int {
	if num < 2 {
		return num
	}
	return fibonacci(num-1) + fibonacci(num-2)
}
 

Final thoughts

Go functions contain a block of code or statements consistent with the logic that they implement. For example, the add() function may add two numbers, the convert() function may convert a specific type to another type, and so on. The idea is to arrange program logic into maintainable parts using functions. Functions leverage reusability of code and can often reduce memory overload considerably. A function usually takes some values as parameters, processes them according to the logic, and returns some value. There can be functions that do not take any parameter nor return any value as well.

Latest Posts

Related Stories