DEV Community

Cover image for The Simple Golang Tutorial Part 3: Functions
Ali Sherief
Ali Sherief

Posted on

The Simple Golang Tutorial Part 3: Functions

#go

This week it's going to be all about functions as we dive deep into Golang’s semantics to enable you to write complex programs.

I pasted many code snippets from Golang’s reference manual, so credits to them.

Functions

First, you need to know what function declarations look like in Golang. Here is their schema:

func (VAR1 TYPE1, ...) NAME RETURN_TYPE {
  /* body */
}
Enter fullscreen mode Exit fullscreen mode

A few important things to note here:

  • All functions are made with the func keyword
  • In golang, the variable names precede their types. This is also true inside function arguments.
  • The name comes after the function signature.
  • Finally, after the signature and name comes the return value.

So the order in which these elements appear may be opposite from what you're used to.

Also, functions can return a tuple containing more than one value like this:

func (VAR1 TYPE1, ...) NAME (RET_VAR1 RET_TYPE1, ...)
Enter fullscreen mode Exit fullscreen mode

So inside the parentheses on the right, we have a tuple that contains not only the type of each item in the return value but also its name since there is more than one return value now.

Now, you might be wondering how you are going to reference multiple return values at once. The answer is, it is not much different from defining multiple return values. Specifically, it's done like this:

a, b, c = f(...)
Enter fullscreen mode Exit fullscreen mode

The variables need to be written in the order the return values are. You can't mix up their order.

Essential Function Statements

You need to know a couple of statements to use functions effectively, such as conditionals, loops, and how to return from a function.

Conditionals

We have if statements that test for arbitrary events and also switch statements that compare a variable against several values.

In Golang, if statements aren’t wrapped around parentheses and look like this:

if x > max {
    x = max
}
Enter fullscreen mode Exit fullscreen mode

They can also have an assignment before the condition. However, this is more of an aesthetic feature than a technical one because you could've done the same thing by writing the assignment before the entire if statement.

if x := f(); x < y {
    return x
} else if x > z {
    return z
} else {
    return y
}
Enter fullscreen mode Exit fullscreen mode

Here I also showcase the use of else if and a final else clause.

Now let's cover the switch statement:

switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}
Enter fullscreen mode Exit fullscreen mode

We can arrange the cases in any order we like and still achieve correct program execution. break statements are not needed after each case, unlike in some other languages.

switch x := f(); {  // missing switch expression means "true"
case x < 0: return -x
default: return x
}
Enter fullscreen mode Exit fullscreen mode

Here we are testing the result of each expression in the case against the value “true” which is the default value to be tested when there's only an assignment in the switch statement like this.

switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}

Enter fullscreen mode Exit fullscreen mode

The default “true” test subject also applies when the switch statement is empty, like this example.

Loops

We have two kinds of loop statements, and both of them use the for keyword. The first kind contains only a conditional and is equivalent to “while” statements in other languages:

for a < b {
    a *= 2
}
Enter fullscreen mode Exit fullscreen mode

While the second kind of loop statement has an initiazation statement and a post-condition statement:

for i := 0; i < 10; i++ {
    f(i)
}
Enter fullscreen mode Exit fullscreen mode

Return statements

Finally, returning from a function is done using the return statement. We can put a value after the return keyword to return a value, which can also be a comma-separated list of values if you want.

Golang also has a break statement that gets you out of a loop, and a continue statement that jumps the program directly to the next loop iteration, skipping all the later statements in the loop in progress.

Essential packages

In Golang, functions are organized in packages and not stand-alone in the global scope. Here are some of the more essential modules you will be using:

  • fmt
  • math
  • os
  • regex
  • sort
  • strings
  • time

We will not cover these packages in extreme detail, but I’ll tell you what each module does and some of the more widely used functions in each.

fmt

The fmt module contains functions to format a string with additional variables and print it to the console, a file, or a string. It also contains functions to read formatted input from these sources.

Among the functions it exports are Printf(), Fprintf() (print to file), Sprintf() (print to string), Scanf(), Fscanf(), and Sscanf(). The naming convention should be easy to follow along with.

Here is an example of Printf() in action:

package main

import (
    "fmt"
)

func main() {
    const name, age = "Kim", 22
    fmt.Printf("%s is %d years old.\n", name, age)

    // It is conventional not to worry about any
    // error returned by Printf.

}
Enter fullscreen mode Exit fullscreen mode

The %s formats a string, while the %d formats an integer.

If, for whatever reason, you are uncomfortable with using format specifiers, Golang also offers a family of Print() functions that take a list of strings as arguments and print them separated by whitespace.

math

This package gives you access to mathematical functions. All of them take and return float64 values and arguments.

Among the functions available are trigonometric functions for Sin, Cos, and Tan, exponential and logarithmic functions, a square root function, minimum and maximum functions, and “floor” and “ceil” functions that move the number to the nearest smallest and largest whole number, respectively.

os

The os module exposes operating system functions. This includes opening and closing files using Open() and Close(), functions to spawn and kill processes, remove and create files, and exit the Golang program using Exit().

regex

This module provides functions to construct regular expressions and searching strings against them. This guide will not cover repulse expressions themselves; it's assumed you already know how to read them.

First, we must compile a regular expression string using Compile(), and this will return a special Regexp object:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`foo.?`)
    fmt.Printf("%q\n", re.FindString("seafood fool"))
    fmt.Printf("%q\n", re.FindString("meat"))
}
Enter fullscreen mode Exit fullscreen mode

MustCompile() is a version of Compile() that panics and aborts the program if the regular| expression string is malformed.

After the regular expression is compiled, then we can search for any string with it using FindString(). And if nothing matches the regular expression, it returns an empty string.

sort

The sort module gives us functions to sort arrays with. Among other types of collections, it can sort string arrays, int arrays, float arrays, and even arrays with user-defined types.

package main

import (
    "fmt"
    "sort"
)

func main() {
    s := []string{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}
    sort.Strings(s)
    fmt.Println(s)
    t := []int{5, 2, 6, 3, 1, 4} // unsorted
    sort.Ints(t)
    fmt.Println(t)
}

Enter fullscreen mode Exit fullscreen mode

It also has functions for performing a binary search on arrays.

strings

This module contains a host of functions for splitting and joining strings, trimming characters from either side of the string, finding the index of characters in a string, manipulating the case of strings, and much more.

time

Finally, this module lets you get the current time as a time object using time.Now(). You can add and subtract time objects from each other using the Add() and Sub(), and this technique allows you to measure elapsed time within programs. It can represent absolute times or questions of times using the same object. It also lets you get each time component, such as the year, month, day, hour, minute, and second, using separate function calls for each.


I haven't covered all the modules, but these are the ones you will find yourself using the most. Keep in mind that Golang has excellent documentation for all of these packages on their website so be sure to check that out too to discover more packages!

Top comments (0)