Understand Functions in Golang: [7 Best Examples]

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]

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)
}
OUTPUT
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-declare.go
Sum of 5 and 8 is: 13

 

In the above example, we have declared a function 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",
    })
}
OUTPUT
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)
}
OUTPUT
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\var-parameter.go
Sum of numbers is: 38

 

In the above example, we have created a function 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:

When using variadic function, variadic parameter is treated as a slice of the specified type.

 

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)
    }
}
OUTPUT
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

 

In the above example, We have declared an anonymous function  with the keyword 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.
Here, we are passing the 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")
}
OUTPUT
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))
    }
}
OUTPUT
PS C:\Users\linuxnasa\OneDrive\Desktop\Go-Dump> go run .\func-return.go
4 5
5 6
6 7

 

In the above code, we have defined a function Add that takes an integer num1 and returns another function. The returned function takes an integer num2 and returns the sum of num1 and num2.
In the main function, We have created two functions,  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.
Inside the for loop, firstAdd(i) is called which calculates the sum of num1(4) and i. Then secondAdd(i) is called which calculates the sum of num1(5) and i. the results are printed on the same line using 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
}
}
}
OUTPUT
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.

 

In the above code, we first check if command-line argument specifying a file name is provided or not. If not, it logs an error message and exit. If file name is provided, it attempts to open the file using os.Open. If there is an error (e.g., file does not exist), it logs the error message and exit.
defer f.Close() is used to ensure that the file  is closed when the function returns, regardless of whether it returns due to an error or after successfully processing the file. A buffer data of size 2048 bytes is created to read the data from the file. Inside the loop, it checks for errors after each read. If an error occur, it logs the message and exits.

 

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.

 

 

 

 

 

 

Leave a Comment