Introduction to Golang: Functions, Loops, Maps, Arrays, and Conditionals
Forty-five years since the invention of the C programming language, lots of languages have been developed — some functional, others object-oriented, and some with the spice of both. Golang is a new kid on the block that is becoming more popular by the day.
Why Go
Go is a statically typed language that is easy to learn and forces you to adhere to good programming habits. Although what is termed good programming habits is a bit blurry these days, Go tries to enforce some rules to help remove certain pitfalls we encounter when writing code, e.g., forcing you to remove unused variables or packages.
All You Need to Get Started
Go has a handful of keywords that we'll be going through in this article. By the end of this section, you should be able to:
- Understand Packages, variables, and functions
- Understand types: arrays, slices, and maps
- Control flow: for, if, else, switch
Packages, variables, and functions
For experienced programmers who have worked with languages like Java, C, or C++, it's de facto to have the main function as the entry point of your application. The same goes for Go.
Packages and imports
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello world")
}
The above code snippet shows two keywords:
-
Package: In Go, a package is like a namespace for your application. Every Go file must have a package name and is referenced by the folder where it’s stored. A
ToUpper
function placed in a string/utility folder will have the package name utility. NB: the file package main seems to be the only package that does not adhere to this rule, meaning the package main can be placed anywhere. -
Import: The
import
keyword is used to import other external methods in Go. The example above is importing the fmt package that we used to print "hello world." In a nutshell, you have just written your first Go program.
You can use Go playground or repl.it to run your “hello world” program.
You can check out Golang’s official site on how to set up Go on your system.
Variables
For those of us coming from the world of JavaScript, good news! Golang uses the var
and const
keywords to declare variables.
package main
import (
"fmt"
)
func main() {
const name string = "enaho Murphy"
var nationality = "Nigeria"
age := 67
fmt.Println(name +" "+ nationality)
}
The above snippet shows the use of const
and var
to declare variables. As in most languages that use const
, this tells the compiler that the variable name cannot be reassigned. Unlike the const
keyword, variables declared with a var
keyword can be reassigned.
Another nitpick is the value at the front of the variables. Those are used to enforce types assigned to variables. If I try to pass an int into the variable name, an error would be thrown.
Below is a list of Golang types:
- int8, int. int32, and int64
- float32 and float64
- string
- bytes
- rune
- uint8, uint32, and uint64
Check out the Golang specs for more types.
One more thing to note is that I did not declare or assign a type to the variable age. Using :=
, Golang automatically evaluates the type you're trying to assign and makes the variable that type. If I try assigning a string to age, that will throw an error.
Functions
package main
import (
"fmt"
)
func main() {
printName()
fmt.Println(Multiply(34, 55))
}
func printName() {
fmt.Println("enaho murphy")
}
func Multiply(a int, b int) int {
return a * b
}
Functions in Go are declared with the func
keyword. As seen in the above snippet, parameters passed into the above function must be type int. If I try passing a string into the multiply function, I'll get an error. Go also forces you to define a type for your return value. If I try returning anything other than an int from the Multiply
function, I'll get an error.
One more thing: Go uses caps to mimic encapsulation. Functions in uppercase can be accessed by functions in other packages. All lowercase functions are private to that package.
There is also a function called the init
function. If declared, Go first runs code in that function before running the main function.
Note: functions in Golang can return more than one value.
Types: Array, Slices, and Maps
Arrays and Slices
Arrays in Golang are the same as slices. Arrays, however, cannot be resized. A slice does not store data — it just points to an array underneath.
Golang gives you this illusion of resizable arrays by constantly reallocating the array and increasing the length by twice the initial value. With this, you don't have to worry about the size constraint of an array.
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
a[3] = "sss"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
The above snippet shows a declaration of an array of type string, which accepts two values. If you have ever programmed before, assigning “Hello” to the array should be familiar to you.
The code snippet above will throw an out of bound context error because we tried to assign three values into an array that only accepts two. Removing the third assignment will fix that error.
Also, note that arrays in Go use a curly bracket to assign values when the variable is declared. That is a short method of dynamically assigning values to arrays. You'll see me use that syntax a lot in this article.
The next code snippet will show you how to make a slice that can take in varying number of assignments.
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
s = append(s, 9, 20, 6, 8, 9)
fmt.Println(s)
}
Slicing our array returns a new array. That returned array is a slice. The slice can be resized. As you can see, I was appending multiple values to s and it worked. You should know, the append will return a new reference, since Go automatically recreates a new array and creates a reference to it. Logging out of the append without assigning the value to s first will return the initial value of s.
Another way to create a slice is to use the make
keyword:
package main
import (
"fmt"
)
func main() {
s := make([]string, 3)
fmt.Println("emp:", s)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("set:", s)
fmt.Println("get:", s[2])
fmt.Println("len:", len(s))
s = append(s, "hello", "world" , "this", "is", "great")
fmt.Println("Len:", len(s), s)
}
As you can see, I was able to append more values to initial declaration of s by creating an array with the make
keyword. Logging out the value will result in a length of eight, and all the append values will show with the initial values.
You should note that if you try to use the s[3] = "hello"
to assign values to a slice that points to an array of 3, it will throw an error. Always remember that slices are pointers to an array.
The append method just creates a new array and returns a pointer to that array. Also, the Len method is used to check the array’s length.
Maps
In a nutshell, a map maps keys to values. Coming from Python, you could call it a dictionary. If you're a Ruby programmer, you could call it a hash. In Golang, we call it a map.
The snippet below shows the two ways we could create maps in Golang.
package main
import (
"fmt"
)
func main() {
var newMap map[string]int
newMap = make(map[string]int)
newMap["age"] = 15
newMap["issn"] = 16273844
fmt.Println(newMap)
var secondMap = map[string]string{
"name": "Enaho Murphy",
"age": "55",
"nationality": "Nigeria",
}
fmt.Println(secondMap["name"])
}
We first declared the type of map and then used the make
keyword to create a new map assigning it to the newMap variable.
The second method creates and initializes the map, adding new values to it. You could call it a shorthand method of creating maps in Go. You can also see this pattern used when creating an array above.
for
, if
, else
, switch
Control flow: Unlike most languages, Golang only has a for
loop. The Golang for
loop is very powerful, as it can be used to iterate through an array, mimic a while
loop, and even call base on multiple statements.
For
The snippet below will show the for
loop in action.
package main
import (
"fmt"
)
func main() {
Print(generateArray(100))
}
func generateArray(num int) []int {
var array = make([]int, num)
var count int = 0
for num > 0 {
count += 1
array[count -1] = count
num -= 1
}
return array
}
func secondGenerateArray(num int) []int {
var array = make([]int, num)
for i := 0; i < num; i +=1 {
array[i] = i + 1
}
return array
}
func Print(arr []int) {
for key, value := range arr {
fmt.Println(key, value)
}
}
From the snippet above, I created three methods:
generateArray
takes in an integer and returns a range of numbers from 1 to the passed-in value. The main point is to show you that thefor
loop in Go can keep executing until a certain condition is met. To create an infinite loop, I just use thefor
keyword without any value and use thebreak
keyword to break out of the loop.
i := 10
for {
fmt.Println("i got caled", i)
if i <= 5 {
fmt.Println("Loop terminated")
break;
}
i -= 1
}
NB: You can also use the continue
keyword in Golang.
secondGenerateArray
: This function uses thefor
loop to iterate over the number passed in. This is a typical loop found in most languages, like JavaScript and C++, comprised of three parts:
init
: Sets the initial value of Icondition
: Sets the condition for the loop to keep iterating. The example states: “if the variable I is less than the number passed in”increment
: For every iteration,increment
is the value of I
When I equal the value passed in, the loop terminates.
I hope you are beginning to see the power of Golang for loops!
-
The last function shows Golang looping over an array. As you’ve probably already noticed, we are looping over the range of an array that returns the key and value.
On each iteration, we're just printing out the key and the value. This pattern is also used to iterate over a map.
func main() {
T := map[string]string {
"name": "Enaho Murphy",
"age": "44",
}
for _, value := range T {
fmt.Println(value)
}
}
Notice that I used an underscore for the key. Golang throws an error when unused variables are declared. Since the range will return two values, by using the underscore, I'm telling Go to ignore the key.
If and Else
Control of a program in Go is pretty straightforward. One thing you might need to wrap your head around is the idea of not using brackets when evaluating conditions.If you're a Pythonista, this should be familiar to you.
package main
import (
"fmt"
"os"
"strings"
)
func main() {
inputs := os.Args
v := strings.Join(inputs[1:], " ")
if v != "" {
fmt.Println("Hello " + v)
} else {
fmt.Println("Hello anonymous user")
}
}
The example above makes use of two Golang packages we have not seen yet. We will use the “os” package to get user inputs.
When that example is ran, any value passed after the file name will be collected in os.Args. This returns an array — the first value is a path to your Golang file and the rest the value you typed after the name of the file.
> go run test.go hello world
fmt.Println(os.Args) // [filepath, hello, world]
By using the Join
method on the strings package, we joined everything, except the file path, by splicing the array returned by os.Args.
I checked whether there was a value in the variable, then printed “hello” with what the user passes in, or, I printed “hello anonymous user.”
Manipulating program flow in Golang is pretty straightforward.
Switch
The switch
statement in Golang is as straightforward as the if
and else
. We can assert a single value and run logical code base on the passed in value.
We will be using the os.Args to get the user inputs and echo different values based on their inputs.
package main
import (
"fmt"
"os"
)
func main() {
inputs := os.Args
switch inputs[1] {
case "help":
fmt.Println("This is all the help you need")
case "greet":
fmt.Println("Hello user")
default:
fmt.Println("You passed no argument")
}
}
Pretty straightforward, right?
Wrapping it Up
Putting it all together, let's implement the binary search algorithm, which takes in an array of sorted numbers and returns the position of the value, the count it took to find the value, and the value itself as a map.
Note: I won’t cover in detail what a binary search array is. This article does not cover that, but here is a great resource on tutorials point that covers more about it.
First, let's use our generate function to create a range of arrays.
func GenerateArray(num int) []int {
var array = make([]int, num)
for i := 0; i < num; i++ {
array[i] = i + 1
}
return array
}
Now that we can generate sorted arrays, let's implement the sorting algorithm.
func BinarySearch(collection []int, value int) map[string]int {
low := 0
high := len(collection) - 1
result := map[string]int{
"value": value,
"count": 0,
"position": -1,
}
for low <= high {
mid := (low + high) / 2
result["count"]++
if collection[low] == value {
result["position"] = mid
break
} else if collection[high] == value {
result["position"] = mid
break
} else if collection[mid] == value {
result["position"] = mid
break
} else if collection[mid] < value {
low = mid + 1
} else {
high = mid - 1
}
}
return result
}
We took the length of the array, added it to the array’s lowest value, and divided it by 2 to get the middle value. We also initiated a map to hold the value, result, and position.
Using a for
loop, we're checking whether the low becomes greater than the high — if it does, then the value is not in that array. By checking whether the mid value equals what we are looking for, we can also terminate the loop if it evaluates to true using break
.
If the middle value is less than the value we're looking for, we know we need to start searching for the middle value. If the value is less than the mid value, we need to start searching before the mid.
We do this iteratively, until we either find the value, or low becomes either equal to or greater than high. Then, the loop terminates, and our map is returned. This algorithm is also called the divide and conquer algorithm.
Putting it all together will give us something like this:
Summary
This article should cover enough content for you to get started with Golang. We still have much to cover, like interfaces and structs, concurrency, and parallelism, which we’ll discuss in a future article
It has been nice writing this article. Please, if you have issues with the code we have written so far, kindly drop a note in the comment box below.