Go is a simple, fast, and concurrent programming language. Its simplicity in design makes it an amazing programming language to work with. Go is currently gaining a lot of popularity, and a lot of organizations now prefer to write their backend in Go.
Go was designed at Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson to improve programming productivity in an era of multicore, networked machines and large codebases.The designers wanted to address criticisms of other languages in use at Google, but keep their useful characteristics:
- Static typing and run-time efficiency (like C)
- Readability and usability (like Python)
- High-performance networking and multiprocessing
Its designers were primarily motivated by their shared dislike of C++.
Go was publicly announced in November 2009,and version 1.0 was released in March 2012. Go is widely used in production at Google and in many other organizations and open-source projects like Kubernetes, Prometheus, and Docker.
In retrospect the Go authors judged Go to be successful due to the overall engineering work around the language, including the runtime support for the language’s concurrency feature.
Although the design of most languages concentrates on innovations in syntax, semantics, or typing, Go is focused on the software development process itself. The principal unusual property of the language itself—concurrency—addressed problems that arose with the proliferation of multicore CPUs in the 2010s. But more significant was the early work that established fundamentals for packaging, dependencies, build, test, deployment, and other workaday tasks of the software development world, aspects that are not usually foremost in language design.
Go Installation for linux
- Download Binary
- Remove old go version (if any)
sudo rm -rf /usr/local/go
- Install go binary
sudo tar -C /usr/local -xzf go1.24.2.linux-amd64.tar.gz
- Add /usr/local/go/bin to the PATH environment variable
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc source ~/.bashrc
- Verify installationOutputs:
go version
go version go1.23.1 linux/amd64
Let’s write some code
- Make a directory
mkdir go-example cd go-example
- Enable dependecy tracking
go mod init example/hello
- Create a file
hello.go
in which to write our code.In this code, we:package main import "fmt" func main() { fmt.Println("Hello, World!") }
- Declare a
main
package (a package is a way to group functions, and it’s made up of all the files in the same directory). - Import the popular
fmt
package, which contains functions for formatting text, including printing to the console. This package is one of the standard library packages we got when we installed Go. - Implement a
main
function to print a message to the console. Amain
function executes by default when we run themain
package.
- Declare a
- Run the codeOutput:
go run hello.go
Hello, World!
The
go run
command is one of many go commands we’ll use to get things done with Go. Use thego help
command to get a list of the others:
govind@debian:~$ go help
Go is a tool for managing Go source code.
Usage:
go <command> [arguments]
The commands are:
bug start a bug report
build compile packages and dependencies
clean remove object files and cached files
doc show documentation for package or symbol
env print Go environment information
fix update packages to use new APIs
fmt gofmt (reformat) package sources
generate generate Go files by processing source
get add dependencies to current module and install them
install compile and install packages and dependencies
list list packages or modules
mod module maintenance
work workspace maintenance
run compile and run Go program
telemetry manage telemetry data and settings
test test packages
tool run specified go tool
version print Go version
vet report likely mistakes in packages
Use "go help <command>" for more information about a command.
Packages and Imports
Go does not support Classes like in OOPs programming languages such as Java, it uses the package system instead. Each package is a directory in your workspace, and each go file must belong to some package. Hence, each file should start with the keyword package
followed by the package name. A go executable must contain package main
.
A package can be imported by using the import
keyword followed by the list of packages inside parenthesis.
The standard library comes preinstalled, with Go, and contains the most essential and useful packages. “fmt” is used to export Println which prints to console.
Go does not allow unused imports.
package main
import (
"fmt"
"log"
"time"
)
Using an external package
When we need our code to do something that might have been implemented by someone else, we can look for a package that has functions we can use in our code.
Let’s Make our printed message a little more interesting with a function from an external module.
- Visit pkg.go.dev and search for a “quote” package.
- Locate and click the rsc.io/quote package in search results (if we see rsc.io/quote/v4, ignore it for now).
- In the Documentation section, under Index, note the list of functions we can call from our code. we’ll use the Go function.
- At the top of this page, note that package quote is included in the rsc.io/quote module.
we can use the pkg.go.dev site to find published modules whose packages have functions we can use in our own code. Packages are published in modules like rsc.io/quote
where others can use them. Modules are improved with new versions over time, and we can upgrade our code to use the improved versions.
Create a file
quote.go
and add the following codepackage main import ( "fmt" "rsc.io/quote" ) func main() { fmt.Println(quote.Go()) }
Add new module requirements and sums.
Go will add the quote module as a requirement, as well as a
go.sum
file for use in authenticating the module.go mod tidy
Run the code to see the message generated by the function we’re calling.
go run quote.go
Output:
Don't communicate by sharing memory, share memory by communicating.
Notice that our code calls the Go function, printing a clever message about communication.
When we ran
go mod tidy
, it located and downloaded thersc.io/quote
module that contains the package you imported. By default, it downloaded the latest version.
Language concepts
1. Variables
Go’s basic primitive types are bool, string, int, uint, float, and complex, the size of the type can be specified next to the type, uint32. A variable is declared by the var
keyword followed by the variable name and the type.
variables can also be initialized with a shorthand notation :=
as Go can infer the type.
Just like imports, unused variables are not allowed.
package main
var x int = 5
var y int = 6
sum := x + y
Also, Go does not use semicolons to end a statement.
An important point to note is how Go scopes variables with a package, a variable is public if the first letter is in Captial, else private, same goes for functions.
package main
X := 5 // public
y := 6 // private
func Add() { // public
}
func add() { // private
}
2. Functions
Functions are an essential part of Go, and of course, the above won’t work as execution has to happen in a function body. Functions are declared with the keyword func
followed by the function name, arguments, and return type. A Go application must contain the main
function which is the entry point to the application. It does not take any arguments or return anything. The opening braces of the function must start at the same level as the function and cannot move to the new line.
function parameters are declared with their name followed by the type and separated by a comma. The return type must be provided if the function returns, as a shortcut the return variable can also be declared to avoid declaring another variable inside the function, here’s an example.
package main
func sum(x int, y int) int {
sum := x + y
return sum
}
// OR
func sum(x int, y int) (sum int) {
sum := x + y
return
}
3. Arrays, Slices, and Maps
Arrays can be declared by simply specifying the datatype next to brackets with an integer denoting the size of the array. Then, arrays can be assigned by their index, a more convenient way to initialize is to use the shorthand syntax along with the data in parenthesis.
package main
var arr [4]int
arr[0] = 1
arr[1] = 2
// OR
arr := [4]int{1,2,3,4}
But there’s a problem here. You cannot modify the length of the array, wouldn’t it be more convenient when you don’t know the size yet? That’s where Slices
come in, slices are simply dynamic arrays. you can declare a slice just like arrays, without specifying the size.
Slices can be really useful in performing a lot of operations. The copy or append function can be used to manipulate the slice. Slices can also be concatenated using the append with the spread operator(…). A slice can be sliced using its indices within the brackets. Below are some examples.
package main
import "fmt"
func main() {
slice := []int{1,2,3,4,5}
slice1 := slice[2:]
slice2 := slice[:2]
slice = append(slice ,4)
slicecat := append(slice, slice...)
fmt.Println(slice, slice1, slice2, slicecat)
}
The append function does not modify the slice but returns a new slice from the given one. Here’s the output.
# output
[1 2 3 4 5 4] [3 4 5] [1 2] [1 2 3 4 5 4 1 2 3 4 5 4]
Maps are equivalent to a HasMap in Java or a Dictionary in python. They store key-value pairs. A map can be created using the make keyword followed by the keyword map and the datatype of the key in brackets and value next to it.
Maps are simple to operate on, they can be assigned values by using the [ ]
operator specifying the key and value, and a key can be removed by using the delete function.
package main
import "fmt"
func main() {
elements := make(map[string]int)
elements["first"] = 1
elements["second"] = 2
fmt.Println(elements)
delete(elements, "first")
fmt.Println(elements)
}
Output:
map[first:1 second:2]
map[second:2]
3. Loops
Loops in Go exist in the simplest form, there is only one looping syntax, the for
loop. The for
loop can be written in multiple ways to meet your looping needs. The first syntax is a familiar one starting with the pointer variable i and followed by condition and incrementation. The below example will print 1 to 5.
package main
import "fmt"
func main() {
arr := []int{1,2,3,4,5}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
Oh! you badly miss the while loop? Don’t worry, Go has you covered, all you have to do is mention the condition with the for loop and use a pointer declared outside the loop just how you would when using a while loop.
package main
import "fmt"
func main() {
arr := []int{1,2,3,4,5}
i := 0
for i < len(arr) {
fmt.Println(arr[i])
i++
}
}
The range function provides an easy way to access the index as well as value.
package main
import "fmt"
func main() {
arr := []int{1,2,3,4,5}
for i,v := range(arr) {
fmt.Println(i, v)
}
}
4. Struct
The struct
keyword is to define a shape to your data. Since Go does not support classes, data of a certain shape requirement can be stored in variables of that type of struct. A struct is created using the keyword type
and its properties can be accessed by the .
operator.
package main
import "fmt"
func main() {
type Animal struct {
Name string
animalType string
}
giraffe := Animal("Giraffe", "Mammal")
fmt.Println(giraffe.Name, giraffe.animalType)
}
5. nil, error, and multiple return values
Go provides some smooth ways to handle the error and nil values. Both error and nil are native built-in types that can be used to perform validation before performing some operation. Go also supports returning multiple types from a function, this can be done using specifying the type within parenthesis in place of the return type.
package main
import "fmt"
func main() {
a,b := sum(5,10)
}
func sum(x int, y int) (sum int, diff int) {
sum = x + y
diff = x - y
return
}
errors or nil can be returned depending on the operation performed using an if check. Here’s an example showing how you can handle errors by checking the input for a square root function.
package main
import (
"fmt"
"math"
"errors"
)
func main() {
result, err := sqrt(25)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
func sqrt(x float64) (float64, error) {
if x < 0 {
return 0 , errors.New("x must be non negative number")
}
retun math.Sqrt(x), nil
}
6. Pointers
Pointers in Go are similar to pointers in other languages, you can refer to the memory address of the variable by prefixing the variable with an ampersand(&)
symbol and dereference it using an asterisk(*)
, by default, go passes arguments by value not reference, you can accomplish this by prefixing that type of the argument in the function with an asterisk(*)
, here’s an example.
package main
import "fmt"
func main() {
i := 5
increment(&i)
fmt.Println(i)
}
func increment(i *int) {
*i++
}
without the &
it’d print 5 as a copy of the variable would have been passed, and once we have the reference, we need to deference the memory to get the value by using *
on the variable again.
That’s it! you should be now ready to write your first program in Go, try practicing the code snippets and if you feel like challenging yourself more, try writing a basic HTTP server using the net
package. This should give you enough practice to write some awesome packages or contribute to your favorite Go repository.
We’ll explore concurrency and other powerful features of Go in another blog—so stay tuned.
Thanks for sticking around and coding along!
Here are some additional resources if you wish to dive deeper.
Until next time happy coding, and go Go!