About Go


Ever since I encountered Golang, it was love at first code, its not only simple to write but also it compiles fast and even it has concurrency inbuilt in it.
Let’s dive deeper into it!
Go is an open source programming language designed for building simple, fast and reliable software.
Why Create GO
So Go was born around November 2009, a time when we already had pre-existing stable programming languages like Python, R, C, Javascript among others. Why was it born? Why did the Go authors see the need of a new language?
The main reason that sets Go apart from other languages include:
It has a strong,static type system. Statically typed is a programming language characteristic in which variable types are explicitly declared and thus are determined at compile time. The main advantage of statically typed languages is Protection from Runtime Errors.
The syntax is C inspired whereby it is aimed at keeping code concise and readable. This is not only for the programmer but to ease compilation.
Go is network aware and concurrent. Concurrency is a program’s ability to do multiple things at the same time that is, two or more tasks that run independently of each other, at about the same time, but remain part of the same program. Python and C were created before concurrency and with the current machines being able to implement it, concurrency is patched into them but Go has been created with this in mind.
It is multi-paradigm, that is both procedural and object oriented. This allows you to look at your use case and apply either that's best.
Backward compatibility - this ensures that as the language grows in future one does not have to migrate
Go Playground
If you would want to test go code online, you can use go playground, which is a web service that runs on go.dev's servers. The service receives a Go program, vets, compiles, links, and runs the program inside a sandbox, then returns the output.
Installing Go
To install go, just follow the directions that I have outlined on my post on the Installing Go.
How to run Go
First off, you can use any code editor or IDE of your choice to write Go code. The one mostly used is Visual Studio Code.
An example of hello world in go:
package main
import "fmt"
func main () {
fmt.Println("Hello World!")
}
Save the file as main.go
To run the above:
$ go run main.go
Let's unpack what we have done above:
a). package main
is the declaration of the main package that will run
- A package is a way to group functions, and it is made up of all files in the same directory
b). import fmt
The import keyword is how to include code from other packages to use within our program
- The
fmt
package contains functions for formatting text including printing to the console
c). func main () {...}
Implement a main function to print the message to the console.
- A main function executes by default when you run the main package.
Variables
A variable is a storage location, with a specific type and associated name. To declare a variable:
package main
import "fmt"
func main() {
// var name type
var i int
var s string
//initialize or assign values
i = 10
s = "Canada"
fmt.Println(i)
fmt.Println(s)
}
Declaration with initialization
You can declare variables and assign values on the same line:
package main
import "fmt"
func main() {
var i int = 10
var s strint = "Canada"
fmt.Println(i)
fmt.Println(s)
}
Declaration with type inference
You can omit the variable type from the declaration, when you are assigning a value to a variable at the time of declaration. The type of the value assigned to the variable will be used as the type of that variable.
package main
import "fmt"
func main() {
var i = 10
var s = "Canada"
fmt.Println(reflect.TypeOf(i)) //reflect.TypeOf returns the type of the value
fmt.Println(reflect.TypeOf(s))
}
Declaration of multiple variables
You can assign values to multiple variables in one line:
package main
import (
"fmt"
)
func main() {
var fname, lname string = "John", "Doe"
var m, n, o = 1, 2, 3
var item, price = "Mobile", 2000
fmt.Println(fname + " " + lname) // you can use + for string concatenation(to combine several strings)
fmt.Println(m + n + o) // returns 6
fmt.Println(item, "-", price) // returns `Mobile - 2000`
}
Short variable declaration :=
There is no need to use the var
keyword to declare the variable type.
package main
import (
"fmt"
"reflect"
)
func main() {
name := "John Doe"
fmt.Println(reflect.TypeOf(name))
}
Zero Values
If you declare a variable without assigning it a value, it will automatically bind a default value
or a zero value
:
package main
import "fmt"
func main() {
var quantity float32 // zero value of float is 0
fmt.Println(quantity)
var price int16 // zero value of int is 0
fmt.Println(price)
var product string // zero value of string is "", an empty string
fmt.Println(product)
var inStock bool // zero value of bool is false
fmt.Println(inStock)
}
Scope of Variables
Golang uses lexical scoping
based on code blocks to determine the scope of variables. Inner block can access its outer block defined variables, but outer block cannot access its inner block defined variables.
package main
import (
"fmt"
)
var s = "Japan"
func main() {
fmt.Println(s)
x := true
if x {
y := 1
if x != false {
fmt.Println(s)
fmt.Println(x)
fmt.Println(y)
}
}
fmt.Println(x)
}
Note: Short variable declaration is allowed only for declaring local variables, that is, variables declared within the function. When you declare variables outside the function, you must do so using the var keyword.
Data types
Below are some GO basic data types:
- Numeric type
a) int: Signed integer types (int8, int16, int32, int64)
var a int = 5
b) Floating-point types: float32, float64
var z float64 = 3.14
String
These are sequences of characters
var str string = "Welcome to Go!"
Boolean
This represents true or false
var isRight bool = true
Array
This is a fixed collection of elements of the same type. You need to define the size. Like below we have an array of 3 strings.
var strArr [3]string = [3]string{"Jane", "John", "Jill"}
Slice
This is a resizable collection built on top of arrays. You do not have to define the size.
var strArr []string = []string{"Jane", "John", "Jill"}
Map
This is unordered collection of key-value pairs:
var m map[string]int = map[string]int{"one": 1, "two": 2, "three": 3}
Struct
This is a composite data type that groups together variables as fields under a single name:
type User struct { Name string Age int } var user1 User = User{"Jil", 23}
Functions
In Go, functions are blocks of code that perform specific tasks, which can be reused throughout the program to save memory, improve readability, and save time. Functions may or may not return a value to the caller.
// multiply() multiplies two integers and returns the result
func multiply(a, b int) int {
return a * b
}
result = multiply(5,10)
Types
Type is the base interface for all data types in Go. All data types (int, float, string, bool) implement the Type interface. You can also create your own types.
The following is the Type
interface:
type Type interface {
// Underlying returns the underlying type of a type.
Underlying() Type
// String returns a string representation of a type.
String() string
}
Methods
Go does not have classes. However, you can define methods on types.
A method is a function with a special receiver argument.
The receiver appears in its own argument list between the func
keyword and the method name.
In this example, the Abs
method has a receiver of type Vertex
named v
.
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X + v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
Interfaces
An interface type is a set of method signatures.
package main
import (
"fmt"
"math"
)
type geometry interface { // Here’s a basic interface for geometric shapes.
area() float64
}
type rect struct { // we’ll implement this interface on rect type.
width, height float64
}
func (r rect) area() float64 { // here we implement the method in the interface
return r.width * r.height
}
func measure(g geometry) { // calling the methods in the geometry interface
fmt.Println(g)
fmt.Println(g.area())
}
func main() {
r := rect{width: 3, height: 4}
// The circle struct type implements the geometry interface, so we can use the instance
// of this struct as arguments to measure.
measure(r)
}
Conditional Statements
In Go, conditional statements allow the execution of specific code blocks based on conditions.
They control the flow of execution in Go programs.
Main conditional statements in Go are:
1. if Statement
- Used to execute code if a condition is
true
.
package main
import "fmt"
func main() {
age := 20
if age >= 18 {
fmt.Println("You are an adult.")
}
}
2. if-else Statement
- Provides an alternative block of code if the condition is
false
.
package main
import "fmt"
func main() {
age := 16
if age >= 18 {
fmt.Println("You are an adult.")
} else {
fmt.Println("You are a minor.")
}
}
3. if-else if-else Statement
- Used when multiple conditions need to be checked.
package main
import "fmt"
func main() {
score := 85
if score >= 90 {
fmt.Println("Grade: A")
} else if score >= 75 {
fmt.Println("Grade: B")
} else {
fmt.Println("Grade: C")
}
}
4. Switch Statement
- A cleaner way to check multiple conditions.
package main
import "fmt"
func main() {
day := "Monday"
switch day {
case "Monday":
fmt.Println("Start of the week!")
case "Friday":
fmt.Println("Weekend is coming!")
default:
fmt.Println("A regular day.")
}
}
Loops
Loops in Go
In Go, loops are used to execute a block of code multiple times. Unlike other languages, Go has only one looping construct: for
loop, which can be used in different ways.
1. Basic for
Loop
Similar to a
for
loop in C, Java, or Python.It consists of three parts: initialization, condition, and increment/decrement.
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
fmt.Println("Iteration:", i)
}
}
2. for as a While
Loop
- If you omit the initialization and increment,
for
behaves like awhile
loop.
package main
import "fmt"
func main() {
i := 1
for i <= 5 { // Works like while(i <= 5)
fmt.Println("Iteration:", i)
i++
}
}
3. Infinite for
Loop
- If you omit all three parts, Go runs an infinite loop.
package main
import "fmt"
func main() {
for {
fmt.Println("This will run forever!")
break // Use break to exit, or it runs infinitely
}
}
4. for
Loop with range
(Iterating Over Arrays/Slices/Maps/Strings)
- The
range
keyword allows iterating over collections like arrays, slices, maps, strings and channels
a). range
over Maps
When iterating over a map,
range
returns both the key and value.The order of iteration is not guaranteed because Go maps are unordered.
package main
import "fmt"
func main() {
studentGrades := map[string]int{"Alice": 90, "Bob": 85, "Charlie": 92}
for key, value := range studentGrades {
fmt.Println("Name:", key, "Grade:", value)
}
}
If you only need the keys, you can ignore the values:
key := range studentGrades { fmt.Println("Student:", key) }
If you only need the values, you can ignore the keys using
_
:_, value := range studentGrades { fmt.Println("Student:", value) }
b). range
Over Slices
- When iterating over a slice,
range
returns both the index and the value.
package main
import "fmt"
func main() {
numbers := []int{10, 20, 30, 40}
for index, value := range numbers {
fmt.Println("Index:", index, "Value:", value)
}
}
If you only need values (not the index), use
_
:for _, value := range numbers { fmt.Println("Value:", value) }
If you only need index:
for index := range numbers { fmt.Println("index:", index) }
c). range
Over Channels
range
can be used to receive values from a channel until it's closed.
package main
import "fmt"
func main() {
ch := make(chan int)
// Sending values to channel in a separate goroutine
go func() {
for i := 1; i <= 3; i++ {
ch <- i
}
close(ch) // Close the channel to stop range iteration
}()
// Receiving values using range
for val := range ch {
fmt.Println("Received:", val)
}
}
Key Notes on Channels:
The loop stops automatically when the channel is closed.
If the channel is not closed, the loop will block (wait forever).
5. Using break
and continue
break
: Exits the loop.continue
: Skips the current iteration and moves to the next one.
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
if i == 3 {
continue // Skips 3
}
fmt.Println("Value:", i)
}
}
Concurrency in Go (Goroutines & Channels)
Go provides built-in concurrency support using goroutines and channels, making it easy to write efficient concurrent programs.
1. Goroutines (Lightweight Threads)
A goroutine is a lightweight thread managed by the Go runtime.
Use the
go
keyword before a function to run it as a goroutine.Goroutines execute asynchronously, meaning the main function won't wait for them to complete unless explicitly told.
package main import ( "fmt" "time" ) func printMessage(message string) { for i := 1; i <= 5; i++ { fmt.Println(message, i) time.Sleep(time.Millisecond * 500) // Simulate work } } func main() { go printMessage("Hello from Goroutine") // Start goroutine printMessage("Hello from Main") // Main function executes normally }
2. Channels (Communication Between Goroutines)
Channels provide safe communication between goroutines.
Use
chan
to define a channel.Sending and receiving data using
<-
ensures goroutines work together.
package main
import "fmt"
func sendData(ch chan string) {
ch <- "Hello from Goroutine" // Send message to channel
}
func main() {
ch := make(chan string) // Create a channel
go sendData(ch) // Start goroutine
message := <-ch // Receive data from channel
fmt.Println(message)
}
3. Buffered Channels
- A buffered channel allows sending multiple values without blocking until the buffer is full.
package main
import "fmt"
func main() {
ch := make(chan string, 2) // Buffered channel with size 2
ch <- "Message 1"
ch <- "Message 2"
fmt.Println(<-ch) // Receive first message
fmt.Println(<-ch) // Receive second message
}
4. select
Statement (Handling Multiple Channels)
select
lets you listen to multiple channels and process whichever one is ready first.
package main
import (
"fmt"
"time"
)
func sendMessages(ch1, ch2 chan string) {
time.Sleep(time.Second)
ch1 <- "Message from ch1"
ch2 <- "Message from ch2"
}
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go sendMessages(ch1, ch2)
select {
case msg := <-ch1:
fmt.Println("Received:", msg)
case msg := <-ch2:
fmt.Println("Received:", msg)
}
}
5. WaitGroups (Syncing Goroutines)
sync.WaitGroup
ensures the main function waits for goroutines to finish.
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Decrement counter when done
fmt.Println("Worker", id, "started")
time.Sleep(time.Second)
fmt.Println("Worker", id, "finished")
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // Increment counter
go worker(i, &wg)
}
wg.Wait() // Wait for all goroutines to complete
fmt.Println("All workers finished")
}
References
Subscribe to my newsletter
Read articles from Irene Mulondu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Irene Mulondu
Irene Mulondu
I am a GIS enthusiast. Mostly what I do is make maps, create and manage GIS softwares and I Iove R and am learning to appreciate Python. So mainly am a learner in GIS and programming and I like to explore integration of various programming algorithms with GIS.