In this tutorial, we will learn about functions in Golang using 7 best examples. In any programming language, functions are a fundamental building block of the language. Functions in Golang share some similarities with functions in other programming languages but also have some unique similarities that set them apart. In the upcoming sections we will look at different aspect of functions from Golang perspective. Let’s get started.
Understand Functions in Golang: [7 Best Examples]
Also read: Golang Arrays vs Slices
We will now look at different features of functions in upcoming sections. If you have prior knowledge of functions from other programming languages, it will not be difficult to understand the functions from Golang perspective.
Declaring and Calling Functions
First thing first, we will look at the the way we declare a function in Golang and how these functions are called with the help of an example. Syntax to declare a function is as follow:
func <function-name> (<comma-separated-input-parameters>) <return-type>
Example-1: Demonstrate Function Declaration
package main import ( "fmt" ) func addNum(num1 int, num2 int) int { //Declaring a function sum := num1 + num2 return sum } func main() { total := addNum(5, 8) //Calling a function fmt.Printf("Sum of %d and %d is: %d ", 5, 8, total) }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-declare.go Sum of 5 and 8 is: 13
addNum
which accepts two parameters and its return type is integer. This function is called from within the main function. It returns the sum of two integers which is stored in variable total
. fmt.Printf
function is used to print total value on the console.
NOTE:
main function is the starting point for every Go program and it does not take any parameter or return any values
Function Parameters
Named and Optional Parameters
Golang does not support named and optional parameters . But we can use a workaround here to simulate named and optional parameters. We can define a struct that has fields that match the desired parameters and pass the struct to the function. Below is the example to demonstrate this concept.
Example-2: Demonstrate Named Parameters
package main import ( "fmt" ) type setEmployee struct { Name string Job string ID int } func getEmployee(employee setEmployee) { fmt.Println("Employee Name:", employee.Name) fmt.Println("Employee Job:", employee.Job) fmt.Println("Employee ID:", employee.ID, "\n") } func main() { getEmployee(setEmployee{ Name: "Alan", ID: 546, }) getEmployee(setEmployee{ Name: "Katty", Job: "Engineer", }) }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\parameters.go Employee Name: Alan Employee Job: Employee ID: 546 Employee Name: Katty Employee Job: Engineer Employee ID: 0
In the above example, We have created a struct setEmployee
which holds three variable, Name Job and ID. We have created a function getEmployee
to which struct is passed as input parameter. We pass the values to struct during function call from within the main function.
Variadic Parameters
The functions which accepts varying number of input parameters are called variadic functions. It expect one mandatory parameter followed by any number of parameters. The variadic parameter must be the last (or only) parameter in the input parameter list. It is indicated with three dots (...)
before the type. fmt.Println()
is an example of variadic function that allows any number of input parameters. Below is the example to demonstrate the variadic parameter.
Example-3: Demonstrate Variadic Parameter
package main import ( "fmt" ) func addNum(nums ...int) int { sum := 0 for _, num := range nums { sum += num } return sum } func main() { total := addNum(5, 8, 10, 15) fmt.Printf("Sum of numbers is: %d\n", total) }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\var-parameter.go Sum of numbers is: 38
addNum()
that takes a variadic parameter named nums
of type integer. This indicate that we can pass any number of integers as input arguments. We are using for loop inside the function to iterate the nums slice and calculate the sum of numbers. In the main function, we have called this function with four parameters (pass any number of parameters) .
NOTE:
Anonymous functions
Also read: Slices in Golang: [14 Easy Examples]
In Golang, we can define new functions within a function and assign them to variables. These inner functions are called anonymous functions. They do not have name. We can also write them inline and call them immediately without assigning them to a variable. Functions declared inside of functions are able to access and modify variables declared in the outer function. Below is the example to demonstrate anonymous functions.
Example-4: Demonstrate Anonymous Function
package main import ( "fmt" ) func main() { for i := 0; i < 5; i++ { func(j int) { fmt.Println("Printing", j, "from inside of an anonymous function") }(i) } }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-anonymous.go Printing 0 from inside of an anonymous function Printing 1 from inside of an anonymous function Printing 2 from inside of an anonymous function Printing 3 from inside of an anonymous function Printing 4 from inside of an anonymous function
func
immediately followed by the input parameters, the return values and the opening braces. It is a compile time error if try to put a function name.i
variable from the for loop in here. It is assigned to the j
input parameter of our anonymous function.
Pass Functions as Parameters
Since functions are values and we can specify the type of a function using its parameter and return type, we can pass functions as parameters to other functions. One example we can consider is sorting slices. There is a function in the sort package called sort.Slice
. It takes in any slice and a function that is used to sort the slice that is passed in. Below is the example to demonstrate sorting a slice of struct.
Example-5: Demonstrate Functions as Parameter
package main import ( "fmt" "sort" ) type Employee struct { Name string Job string ID int } func main() { employee := []Employee{ {"Alice", "Engineer", 554}, {"Bob", "Operator", 555}, {"Katty", "Assistant", 556}, } fmt.Println("Employee details without sorting", employee, "\n") //sort by Job sort.Slice(employee, func(i, j int) bool { return employee[i].Job < employee[j].Job }) fmt.Println("Employee details after sorting by Job", employee, "\n") //sort by ID sort.Slice(employee, func(i, j int) bool { return employee[i].ID < employee[j].ID }) fmt.Println("Employee details after sorting by ID", employee, "\n") }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-pass.go Employee details without sorting [{Alice Engineer 554} {Bob Operator 555} {Katty Assistant 556}] Employee details after sorting by Job [{Katty Assistant 556} {Alice Engineer 554} {Bob Operator 555}] Employee details after sorting by ID [{Alice Engineer 554} {Bob Operator 555} {Katty Assistant 556}]
In the above example, we have created Employee
struct type with three fields, Name, Job and ID. In the main function, a slice of Employee objects named employee
is created. It contains three employee records with different names, jobs and IDs. We first print the employee details before any sorting. Then we sort the employee slice using function sort.Slice
based on Job and prints the employee records. After this, we again sort the employee slice but this time based on ID and again prints the records.
Return Functions from Functions
In Golang, we can also define functions that return other functions. It allows us to create higher order functions that customize behavior based on the returned function. This is possible because functions in Go are first-class citizens, meaning they can be assigned to variables, passed as arguments and returned as values. Below is the example to demonstrate the concept
Example-6: Demonstrate Function return from Function
package main import ( "fmt" ) // Add is a function that takes an integer num1 and returns a function. func Add(num1 int) func(int) int { // The returned function takes an integer num2 and returns the sum of num1 and num2. return func(num2 int) int { return num1 + num2 } } func main() { // Create two functions, firstAdd and secondAdd, using the Add function. firstAdd := Add(4) secondAdd := Add(5) // Loop from 0 to 2 (inclusive). for i := 0; i < 3; i++ { // Call the firstAdd function with the current value of 'i' and print the result. // Then, call the secondAdd function with the current value of 'i' and print the result. fmt.Println(firstAdd(i), secondAdd(i)) } }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-return.go 4 5 5 6 6 7
firstAdd
and secondAdd
by calling Add function with input arguments 4 and 5 respectively. These returned functions capture the values of num1(4 and 5 ) from their respective calls.fmt.Println
.
Defer Keyword
Any program often creates temporary resources like files or network connections that must be cleaned up irrespective of how many exit points a function has or whether a function completed successfully or not. In Golang, the cleanup code is attached to the function with the defer keyword. Below is the code to demonstrate the usage of defer keyword.
Example-7: Demonstrate Defer Keyword
package main import ( "io" "log" "os" ) func main() { // Check if a file name is provided as a command-line argument if len(os.Args) < 2 { log.Fatal("no file specified") } // Open the file for reading f, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } defer f.Close() // Create a buffer to store data read from the file data := make([]byte, 2048) // Loop to read and print data from the file for { // Read data from the file into the buffer count, err := f.Read(data) // Print the data read to the standard output os.Stdout.Write(data[:count]) // Check for errors if err != nil { if err != io.EOF { log.Fatal(err) } break } } }
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-defer.go 2023/09/01 12:07:04 No file is found in input argument exit status 1 PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-defer.go .\inputFile.txt 2023/09/01 12:07:14 open .\inputFile.txt: The system cannot find the file specified. exit status 1 PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-defer.go .\inputFile.txt Congratulations, We just executed the code to demonstrate the defer keyword in Golang.
Summary
We looked at different aspect of functions in Golang, how they are similar to functions in other languages and their unique features. You can practice all these concept in Go playground if do not have a local setup handy.