This page looks best with JavaScript enabled

Go functions

 ·  🎃 kr0m

In a previous article, we covered the basics of the Go language Go basics . This time, we will delve deeper into Go’s functions.
- Function declaration.
- Multiple return values.
- Functions as types.
- Recursivity.
- Methods.
- Functions with variable input.


If you are new to the world of Go, I recommend the following previous articles:


Function declaration:

Inside the parentheses, the types of the input variables are indicated.

package main

import "fmt"

func main() {
	repeat("AlfaExploit", 5)
}

func repeat(word string, reps int) {
	for i := 0; i < reps; i++ {
		fmt.Println(word)
	}
}

If the function returns a value, the type of the returned value will be indicated outside the parentheses:

package main

import "fmt"

func addition(a, b int) int {
    return a + b
}

func main() {
    result := addition(3, 5)
    fmt.Println(result)
}

Multiple return values:

It is similar to returning an array of values.

package main

import "fmt"

func divisionAndRemainder(dividend, divisor int) (int, int) {
    quotient := dividend / divisor
    remainder := dividend % divisor
    return quotient, remainder
}

func main() {
    quotient, remainder := divisionAndRemainder(10, 3)
    fmt.Println(quotient, remainder)
}

Functions as types:

It’s about using a variable as a function, in this example, the variable operation behaves as if it were the multiplication function.

package main

import "fmt"

type Operation func(int, int) int

func multiplication(a, b int) int {
    return a * b
}

func main() {
    var operation Operation = multiplication
    result := operation(2, 3)
    fmt.Println(result)
}

Recursivity:

Recursion can consume more resources than non-recursive solutions, but it simplifies the code.

A basic example would be calculating the factorial of a given number.

package main

import "fmt"

func factorial(n int) int {
    if n <= 1 {
        return 1
    }
    return n * factorial(n-1)
}

func main() {
    result := factorial(3)
    fmt.Println(result)
}

As an example, let’s assume n is 3, so the code of the factorial function that calls itself would be equivalent to calculating:

n * factorial(n-1)
factorial(3): 3 * factorial(3-1) -> 3 * factorial(2)
factorial(2): 2 * factorial(2-1) -> 2 * factorial(1)
factorial(1): 1

Therefore, we can see that:

factorial(3): 3 * factorial(2)
factorial(2): 2 * factorial(1)
factorial(1): 1

So, substituting, we get:

factorial(3): 3 * factorial(2)
factorial(2): 2 * 1

And finally:

factorial(3): 3 * 2 * 1

Another really useful example is when we need to list a directory tree:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "path/filepath"
)

func scanDirectory(path string) error {
    fmt.Println(path)
    files, err := ioutil.ReadDir(path)
    if err != nil {
        fmt.Printf("Returning error from scanDirectory(\"%s\") call\n", path)
        return err
    }
    for _, file := range files {
        filePath := filepath.Join(path, file.Name())
        if file.IsDir() {
            err := scanDirectory(filePath)
            if err != nil {
                fmt.Printf("Returning error from scanDirectory(\"%s\") call\n", path)
                return err
            }
        } else {
            fmt.Println(filePath)
        }
    }
    return nil
}

func main() {
    err := scanDirectory("my_huge_directory")
    if err != nil {
        log.Fatal(err)
    }
}

Methods:

Go is not an object-oriented language in the traditional sense, but it supports encapsulation, interfaces, and methods. In this section, we’ll focus on the latter to understand how to link methods to types.

Methods offer several advantages over using functions:

  • Methods are logically linked to types.
  • Method names can be reused across different types.

In this example, we’ll link a structure type to the area() method. In this method, we obtain a copy of the object itself, which Go refers to as a receiver; in some programming languages, this is known as this. The idiomatic way to name the receiver is to use the first letter of the object type.

package main

import "fmt"

type rectangle struct {
    Base   int
    Height int
}

func (r rectangle) area() int {
    return r.Base * r.Height
}

func main() {
    // Assign structure variable values
    rect := rectangle{Base: 3, Height: 4}
    // rect structure moreover has area method available
    // Call structure method
    area := rect.area()
    fmt.Println(area)
}

Methods don’t have to be limited to structures; they can also be linked to primitive types. To do this, you need to create an alias for the type, in this case, myInt, and assign it as the type of the method’s receiver. In this example, we’ve also defined the method’s input parameter and return value to be of the same type. Let’s see the following example.

package main

import "fmt"

type myInt int

func (a myInt) add(b myInt) myInt {
    return a + b
}

func main() {
    num1 := myInt(5)
    num2 := myInt(10)
    sum := num1.add(num2)
    fmt.Println("Sum is: ", sum)
}

Functions with variable input:

A variadic function is one that has a variable number of input parameters. The only requirements are that all variadic variables are of the same type and that it is the last one in the list of arguments.

These variables receive the arguments separated by commas and convert them into an array of elements. We can see its functionality in the following example.

package main

import "fmt"

func addition(nums ...int) int {
    fmt.Println(nums)
    result := 0
    for _, num := range nums {
        result += num
    }
    return result
}

func main() {
    total := addition(1, 2, 3)
    fmt.Println(total)

    total = addition(1, 2, 3, 4)
    fmt.Println(total)
}

If, on the other hand, we have a slice and want to pass it to the function, we must indicate it so that the function does not perform a double conversion from array to array.

package main

import "fmt"

func addition(nums ...int) int {
    fmt.Println(nums)
    result := 0
    for _, num := range nums {
        result += num
    }
    return result
}

func main() {
    testSlice := []int{1, 2, 3}
    total := addition(testSlice...)
    fmt.Println(total)

    testSlice = []int{1, 2, 3, 4}
    total = addition(testSlice...)
    fmt.Println(total)
}
If you liked the article, you can treat me to a RedBull here