Golang Tutorial: Learn Golang by Examples

Golang Tutorial: Learn Golang by Examples

Google developed Go to better handle the issues presented by large-scale programming. Get started with learning Golang in this tutorial.

Google developed Go to better handle the issues presented by large-scale programming. Get started with learning Golang in this tutorial.

Golang has become one of the most trending languages in the developer community. Go provides the best of both worlds by striking a balance between dynamic and statically compiled languages. The code is easy to read, the specifications are short, and it still includes a built-in web server! Throughout this Golang tutorial, not only will we be covering the reasons that make Go such a fantastic open-source language, we will also go over a majority of its concepts.

Following are the topics that we will cover throughout this Golang tutorial:

  • Why Learn Golang?
  • What Makes Golang Special?
  • Hello World: First Golang Program
  • Variables and Constants
  • Data Types
  • Operators
  • Pointers
  • Printf
  • Loops
  • Decision-Making
  • Arrays
  • Maps
  • Functions
  • Recursion
  • Defer, Recover, Panic
  • Structures
  • Interfaces
  • Simple Webserver Using Go

Before you learn any language, you should always know why you’re learning the language. Every language serves a special purpose, and the same goes for Golang. So why exactly should someone learn Golang? Well, Golang was built by Google to help solve problems faced by developers at Google, where lots of big programs are built for server software that runs on massive clusters. Before Go, Google was using languages like C++ and Java to solve problems, but these languages didn’t really have the fluidity and ease of construction that was needed for problems of such scale. Keeping these things in mind, a few years ago Ken Thompson and Robert Greaser thought about building a new language that would be good for these kinds of problems, and hence Golang was born. Basically, if you’re trying to solve a problem of enormous scale or just need efficient and scalable code, Go should be your “Go-to” language!

What Makes Golang Special?

The existing languages have been good enough for large-scale programming until recent years, but there have been big changes in the computing environment in the last decade. These changes have included a lot of networking and a lot of cluster computing — or the cloud, as common folk might know it by. The languages that were being used to implement services until now are at least 10 to 20 years old, so there are a lot of properties of a modern computing environment that these languages don’t address directly. Therefore, having a modern language that works really well in the modern computing environment is actually very important. You also want it to be efficient, because you’re going to be running it on hundreds or maybe even thousands of machines. You don’t want to waste resources, either, by having an inefficient interpreter or some of the problems that generally come up with virtual machine implementations.

Golang ticks all these boxes, and hence has garnered much-deserved fame in developer communities.

Hello World: First Golang Program
package main

import "fmt"

func main () {

fmt.Println("Hello World! This is my first Golang programme")

}

Let’s go over the code line by line.

The first line is a package declaration. Every Go program must belong to a package, and this particular program belongs to the “main” package. Next, we import the “fmt” or format library which provides the developer with a wide array of functions that allows formatting of output. Then we create the main function, which is the first function that is invoked when a Go program is executed. In the main function, we simply invoke the ‘Println’ function to print our statement.

Variables and Constants

What exactly is a variable? A variable is nothing but a name given to a storage area that programs can manipulate. Each variable in Go has a specific type, which determines the size and layout of the variable’s memory, the range of values that can be stored within that memory, and the set of operations that can be applied to the variable. Next, constants refer to fixed values that the program may not alter during its execution. These fixed values are also called literals. Constants can be of any of the basic data types like an integer constant, a floating constant, a character constant, or a string literal. There are also enumeration constants as well. Constants are treated just like regular variables, except that their values cannot be modified after their definition.

package main

import "fmt"

func main () {

var x int = 5 //declaration of variable x

var (
a = 10
b = 15 //declaration of multiple variables
)

y := 7 // shorthand declaration of variables

const pi float64 = 3.14272345 //declaration of constants

var name string = "Aryya Paul" //declaration of a string
}


Data Types

Operators

Golang has the three general types of operators that are prevalent in every major programming language.

Pointers

Now it’s time to see how pointers work in Go. Pointers in Go are easy and fun to learn. Some Go programming tasks are performed more easily with pointers, and other tasks, such as call by reference, cannot be performed without using pointers. So it becomes necessary to learn pointers to become a perfect Go programmer. As you know, every variable is a memory location and every memory location has its address defined which can be accessed using an ampersand (&), which denotes an address in memory.

package main

import "fmt"
// POINTERS

func main() {

// We pass the value of a variable to the function
x := 0
changeVal(x)
fmt.Println("x =",x)

// If we pass a reference to the variable we can change the value
// in a function
changeVal(&x)
fmt.Println("x =",x)

// Get the address x points to with &
fmt.Println("Memory Address for x =", &x)

// We can also generate a pointer with new

}

func changeVal(x int) {

// Has no effect on the value of x in main()
x = 2

}

// * signals that we are being sent a reference to the value
func changeXValNow(x *int){

// Change the value at the memory address referenced by the pointer
// * gives us access to the value the pointer points at

*x = 2 // Store 2 in the memory address x refers to

}

}

Printf

Printf is used for format printing our outputs in Golang. It is a part of the format (fmt) library. Below is a table listing out the noteworthy uses of Printf function.

Ok, it’s time we move on to loops.

Loops

If you’re new to programming, a loop is a basic iterating mechanism in computer science and it’s used mostly when you need to perform a repetitive pattern in programming. Now in most programming languages, there are three types of loops, namely for, while(exit controlled) and do-while(entry controlled) but Golang has only one type of loop that is the ‘for’ loop. The syntax of go allows while loops to be implemented with the syntax of a ‘for’ loop.

package main

import "fmt"

func main() {

// For loops

i := 1

for i <= 10 {
fmt.Println(i)

// Shorthand for i = i + 1

i++
}

// Relational Operators include ==, !=, <, >, <=, and >=

// You can also define a for loop like this, but you need semicolons

for j := 0; j < 5; j++ {

fmt.Println(j);

}

}

Decision-Making

Decision-making is a critical part of programming. In Golang, we can implement decision-making using the ‘if-else’ and ‘switch’ keywords. Let’s see how Golang implements decision making with this piece of code below:

package main

import "fmt"

func main() {

// If Statement

age := 15

if age >= 16 {
fmt.Println("Adult")
} else {
fmt.Println("Not an adult")
}

// You can use else if perform different actions, but once a match
// is reached the rest of the conditions aren't checked

if age >= 16 {
fmt.Println("in school")
} else if age >= 18 {
fmt.Println("in college")
} else {
fmt.Println("probably dead")
}

// Switch statements are used when you have limited options

switch age {
case 16: fmt.Println("Go Drive")
case 18: fmt.Println("Go Vote")
default: fmt.Println("Go Have Fun")
}

}


Arrays

An array is a data structure in programming that is used to containerize data of the same type. For example, if you were to store all the student name of a certain class, you would use a string array to store them all. The code below shows how arrays are implemented in Golang.

package main

import "fmt"

func main() {

// An Array holds a fixed number of values of the same type

var favNums2[5] float64

favNums2[0] = 163
favNums2[1] = 78557
favNums2[2] = 691
favNums2[3] = 3.141
favNums2[4] = 1.618

// You access the value by supplying the index number

fmt.Println(favNums2[3])

// Another way of initializing an array

favNums3 := [5]float64 { 1, 2, 3, 4, 5 }

// How to iterate through an array (Use _ if a value isn't used)

for i, value := range favNums3 {

fmt.Println(value, i)

}

// Slices are like arrays but you leave out the size

numSlice := []int {5,4,3,2,1}

// You can create a slice by defining the first index value to
// take through the last

numSlice2 := numSlice[3:5] // numSlice3 == [2,1]

fmt.Println("numSlice2[0] =", numSlice2[0])

// If you don't supply the first index it defaults to 0
// If you don't supply the last index it defaults to max

fmt.Println("numSlice[:2] =", numSlice[:2])

fmt.Println("numSlice[2:] =", numSlice[2:])

// You can also create an empty slice and define the data type,
// length (receive value of 0), capacity (max size)

numSlice3 := make([]int, 5, 10)

// You can copy a slice to another

copy(numSlice3, numSlice)

fmt.Println(numSlice3[0])

// Append values to the end of a slice

numSlice3 = append(numSlice3, 0, -1)

fmt.Println(numSlice3[6])

}


Maps

Besides arrays, we also have another data structure called “Maps” which maps unique keys to values. A key is an object that you use to retrieve a value at a later date. Given a key and a value, you can store the value in a Map object. After the value is stored, you can retrieve it by using its key.

package main

import "fmt"

func main() {

// A Map is a collection of key value pairs
// Created with varName := make(map[keyType] valueType)

presAge := make(map[string] int)

presAge["Narendra Modi"] = 42

fmt.Println(presAge["Narendra Modi"])

// Get the number of items in the Map

fmt.Println(len(presAge))

// The size changes when a new item is added

presAge["Rahul Gandhi"] = 43
fmt.Println(len(presAge))

// We can delete by passing the key to delete

delete(presAge, "Rahul Gandhi")
fmt.Println(len(presAge))

}

Next up, let’s move on to functions.

Functions

A function is a group of statements that together perform a task. Every Go program has at least one function, which is main(). You can divide your code into separate functions. How you divide your code among different functions is up to you, but logically, the division should be such that each function performs a specific task. A function declaration tells the compiler about a function name, return type, and parameters.

package main

import "fmt"

func main () {

fmt.Println("5 + 4 = ", add(5,4))
fmt.Println(subtract(1,2,3,4,5))

}

func add(a,b int) int {

return a+b

}

func subtract(args ... int) {

sub := 0

for _, value := range args {
sub -= value
}

return sub

}


Recursion

Recursion is the process of repeating items in a self-similar way. The same concept applies to programming languages as well. If a program allows calling a function inside the same function, then it is called a ‘recursive function’ call. GoLang supports recursion i.e, it allows a function to call itself. But while using recursion, programmers need to be careful to define an exit condition from the function, otherwise, it will go on to become an infinite loop.

package main

import "fmt"

func main () {

fmt.Println(factorial(5))

}

func factorial(num int) int {

if num == 0 {

return 1
}
return num * factorial(num-1)
}


Defer, Panic, and Recover

**Defer **statement defers the execution of a function until the surrounding function returns. They are generally used to execute necessary closing statements — for example, closing a file after you are done with it. Multiple defers are pushed into stack and executes in Last In First Out (LIFO) order. Defer is generally used to clean up resources like a file, database connection, etc.

**Panic **is similar to throwing an exception like other languages. Generally when a panic is called, then the normal execution flow stops immediately, but the deferred functions are executed normally. It is a built-in function in Golang.

Recover is another built-in function in Go. It helps to regain the normal flow of execution after a panic. Generally, it used with a defer statement to recover panic in a goroutine.

package main

import "fmt"

func main() {

// Defer executes a function after the inclosing function finishes
// Defer can be used to keep functions together in a logical way
// but at the same time execute one last as a clean up operation
// Ex. Defer closing a file after we open it and perform operations

defer printTwo()
printOne()

// Use recover() to catch a division by 0 error

fmt.Println(Div(3, 0))
fmt.Println(Div(3, 2))

// We can catch our own errors and recover with panic & recover

demPanic()

}

func factorial(num int) int {
if num == 0 {
return 1
}
return num * factorial(num - 1)
}

// Used to demonstrate defer

func printOne(){ fmt.Println(1)}

func printTwo(){ fmt.Println(2)}

// If an error occurs we can catch the error with recover and allow
// code to continue to execute

func Div(num1, num2 int) int {
defer func() {
fmt.Println(recover())
}()
solution := num1 / num2
return solution
}

// Demonstrate how to call panic and handle it with recover

func demPanic(){

defer func() {

// If I didn't print the message nothing would show

fmt.Println(recover())

}()
panic("PANIC")

}

Structure

Go allow you to define variables that can hold several data items of the same kind. A structure is another user-defined data type available in Go programming, which allows you to combine data items of different kinds. Structures are used to represent a record. Suppose you want to keep track of the books in a library. You might want to track the following attributes of each book:

  • Why Learn Golang?
  • What Makes Golang Special?
  • Hello World: First Golang Program
  • Variables and Constants
  • Data Types
  • Operators
  • Pointers
  • Printf
  • Loops
  • Decision-Making
  • Arrays
  • Maps
  • Functions
  • Recursion
  • Defer, Recover, Panic
  • Structures
  • Interfaces
  • Simple Webserver Using Go

In such a scenario, structures are highly useful. To define a structure, you must use type and struct statements. The struct statement defines a new data type, with multiple members for your program. The type statement binds a name with the type which is a struct in our case.

package main

import "fmt"

// STRUCTS

func main() {

rect1 := Rectangle{height: 10, width: 10}

fmt.Println("Rectangle is", rect1.width, "wide")

fmt.Println("Area of the rectangle =", rect1.area())

}

type Rectangle struct{

height float64
width float64
}

func (rect *Rectangle) area() float64{

return rect.width * rect.height

}


Interface

Go programming provides another data type called interfaces which represents a set of method signatures. The struct data type implements these interfaces to have method definitions for the method signature of the interfaces.

package main

import "fmt"
import "math"

// STRUCTS AND INTERFACES

func main() {

rect := Rectangle{20, 50}
circ := Circle{4}

fmt.Println("Rectangle Area =", getArea(rect))
fmt.Println("Circle Area =", getArea(circ))

}

// An interface defines a list of methods that a type must implement
// If that type implements those methods the proper method is executed
// even if the original is referred to with the interface name

type Shape interface {
area() float64
}

type Rectangle struct{
height float64
width float64
}

type Circle struct{
radius float64
}

func (r Rectangle) area() float64 {
return r.height * r.width
}

func (c Circle) area() float64 {
return math.Pi * math.Pow(c.radius, 2)
} 

func getArea(shape Shape) float64{

return shape.area()

}

Simple Webserver With Go

Go also provides us with the ability to set up a simple web server in a matter of seconds. It goes to show how robust and powerful Go libraries are.

package main

import (
"fmt"
"net/http"
)

// CREATE A HTTP SERVER

// http.ResponseWriter assembles the servers response and writes to 
// the client
// http.Request is the clients request
func handler(w http.ResponseWriter, r *http.Request) {

// Writes to the client
fmt.Fprintf(w, "Hello World\n")
}

func handler2(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello Earth\n")
}

func main() {

// Calls for function handlers output to match the directory /
http.HandleFunc("/", handler)

// Calls for function handler2 output to match directory /earth
http.HandleFunc("/earth", handler2)

// Listen to port 8080 and handle requests
http.ListenAndServe(":8080", nil)
}

That’s it for this Golang tutorial blog post. I hope you guys enjoyed reading it, and leave confident enough to practice the fundamentals of Golang on your own.

Learn More

Go: The Complete Developer’s Guide (Golang)

Learn How To Code: Google’s Go (golang) Programming Language

Web Development w/ Google’s Go (golang) Programming Language

Build Realtime Apps | React Js, Golang & RethinkDB

Google Golang Masterclass

Advanced Google’s Go (golang) Programming Course

Go Programming and Why should you learn Go Language?

Go Programming and Why should you learn Go Language?

Go provides you high performance like C/C++, super efficient concurrency handling like Java and fun to code like Python/Perl. Go with Golang and why go is the best programming language in the world and Why should you learn Go Language?

Why Learn Go Lang - Should I go with 'Go' | Brief Intro to Go Language

Go with Golang and why go is the best programming language in the world.

We will talk about:

  1. Power of GoLang
  2. Is Go for everyone
  3. Who said Go is better than Nodejs
  4. Who are the creators of GoLang
  5. Why GoLang was created by Google
  6. Why Learn of GoLang
  7. Companies using GoLang
  8. What GoLang have and what not
  9. GoLang Garbage Collection
  10. GoLang Concurrency
  11. Recommended Books for Learning GoLang

Rust vs. Go: Should I Rust, or Should I Go

Rust vs. Go: Should I Rust, or Should I Go

Well both Rust and Go provide amazing performance. Should you write you’re next big thing with Rust or with Go? Go is fast and powerful, but it avoids bogging the developer down, focusing instead on simplicity and uniformity. Rust. If on the other hand, wringing out every last ounce of performance is a necessity, then Rust should be your choice. Rust is more of a competitor to C++ than it is with Go.

Should I stay, or should I go?” Great song by the band The Clash. I’m listening to it, right now, while I’m writing this article. The song debuted back in 1982, a long time ago. Back then, I was just a kid exploring a new hobby — programming my Atari 2600. The first video game I ever wrote was written using 6502 Assembly for that console. The compiler for it cost about $65, if I recall, which at the time equated to mowing ~13 or so lawns.

The game was simple: using the joystick, maneuver your spaceship through a randomly generated scrolling cave. The cave walls were sinusoidal, scrolling vertically on the left and right sides of the screen, and you had to make sure your craft didn’t crash into them. I know, I know: Not that sophisticated. But I was only ten or eleven years old at the time.

Despite the “power” of the processor, computing sine values at run-time was simply too much for it. So, using my handy Texas Instruments calculator, I pre-calculated a bunch of the sine values, carefully writing them down on paper, and then entering them in as constants for the game. This greatly enhanced the performance of the game, and made it usable.

So what’s my point? What’s any of this got to do with Rust or Go?

Today’s languages are far more advanced than 6502 Assembly, which make it easier to write complex programs. It took a lot of my time to write that game, and I could do it much faster today, with less code than I did back then. But which language today provides that magic combination of simplicity and power?

Well both Rust and Go provide amazing performance. They both compile to machine code, the Holy Grail of performance. And with today’s processing power, developers can do amazing things with either of these languages. So the question is: Should you write you’re next big thing with Rust or with Go?

With a quick search, you can easily find several articles that go into detail about the differences between the two languages. But the focus of this article is the bang for the buck, that magic combination of performance per line of code.

To put it another way, where is that sweet spot of simple code and top-end performance? And in this case, is it Rust, or is it Go?
There really isn’t any argument: Rust is faster than Go. In the benchmarks above, Rust was faster, and in some cases, an order of magnitude faster.

But before you run off choosing to write everything in Rust, consider that Go wasn’t that far behind it in many of those benchmarks, and it’s still much faster than the likes of Java, C#, JavaScript, Python and so on. So in other words, it’s almost a wash between Rust and Go on the axis of performance. Now, if what you’re building needs to wring out every last ounce of performance, then by all means, choose Rust. But if what you need is top-of-the-line performance, then you’ll be ahead of the game choosing either of these two languages.

So then we’re down to the complexity of the code. This is where things can be muddy since this can be more subjective than performance benchmarks. Let’s look at a simple exercise: building a small web server that prints out “Hello World” when it receives an HTTP request. To do this in Rust, it looks something like this:

use std::net::{TcpStream, TcpListener};
use std::io::{Read, Write};
use std::thread;


fn handle_read(mut stream: &TcpStream) {
    let mut buf = [0u8; 4096];
    match stream.read(&mut buf) {
        Ok(_) => {
            let req_str = String::from_utf8_lossy(&buf);
            println!("{}", req_str);
            },
        Err(e) => println!("Unable to read stream: {}", e),
    }
}

fn handle_write(mut stream: TcpStream) {
    let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><body>Hello world</body></html>\r\n";
    match stream.write(response) {
        Ok(n) => println!("Response sent: {} bytes", n),
        Err(e) => println!("Failed sending response: {}", e),
    }
}

fn handle_client(stream: TcpStream) {
    handle_read(&stream);
    handle_write(stream);
}

fn main() {
    let port = "8080";
    let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap();
    println!("Listening for connections on port {}", port);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(|| {
                    handle_client(stream)
                });
            }
            Err(e) => {
                println!("Unable to connect: {}", e);
            }
        }
    }
}

Something pretty similar in Go looks like this:

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
)

type handler struct{}

func (theHandler *handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	log.Printf("Received request: %s\n", request.URL)
	log.Printf("%v\n", request)
	io.WriteString(writer, "Hello world!")
}

const port = "8080"

func main() {
	server := http.Server{
		Addr:    fmt.Sprintf(":%s", port),
		Handler: &handler{},
	}

	server.ListenAndServe()
}

Now, they are not 100% exactly the same, but they are close enough. The difference between them is ~20 lines of code. Rust definitely forces the developer to consider more, and thus write more code than Go.

Another example: Consider one of the more difficult aspects of software development: multi-threading. When tackling something like this, as you undoubtedly would when building an HTTP server, there’s a lot to think about:

  • You need to ensure everything you design is thread safe (locks)
  • You need to handle communication between threads (channels)
  • You have to design with concurrency and parallelism in mind (threads and routines)

Both Rust and Go handle these hurdles really efficiently, but Go requires less effort. With Rust, you have way more options, and thus more power, when spawning threads. Just look at some of the documentation on this. Here’s just one way to spawn a thread in Rust:

use std::thread;

let handler = thread::spawn(|| {
    // thread code
});

handler.join().unwrap();

On the other hand, here’s how to create something similar using Go:

go someFunction(args)

Another crucial part of writing code is handling errors. Here I think Rust and Go are quite similar. Rust enables the developer to handle errors cases through the use of the enum return types: Option<T>and Result<T, E>. The Option<T> will return either None or Some(T) whereas Result<T, E> will return either Ok(T) or Err(T). Given that most of Rust’s own libraries, as well as other third-party libraries, return one of these types, the developer will usually have to handle the case where nothing is returned, or where an error is returned.

Here’s a simple example of the Result type being returned by a function in Rust:

fn foo_divide(a: f32, b: f32) -> Result<f32, &'static str> {
    if b == 0.0 {
        Err("divide by zero error!")
    } else {
        Ok(a / b)
    }
}fn main() {
    match foo_divide(5.0, 4.0) {
        Err(err) => println!("{}", err),
        Ok(result) => println!("5 / 4 = {}", result),
    }
}

Notice that the Err case must be handled within the match statement.

Go, on the other hand, leaves this more up to the developer, since errors can be ignored using the _. However, idiomatic Go strongly recommends returning an error, especially since functions in Go can return multiple values. Therefore, it’s easy to have functions return their intended value along with an error, if there is one.

Here is the corresponding example from above done in Go:

func fooDivide(a float32, b float32) (float32, error) {
    if b == 0 {
        return 0, errors.New("divide by zero error!")
    }    return a / b, nil
}func main() {
    result, err := fooDivide(5, 4)
    if err != nil {
       log.Printf("an error occurred: %v", err)
    } else {
       log.Printf("The answer is: 5 / 4 = %f", result)
    }
}

Notice that this line:

result, err := fooDivide(5, 4)

could have been written as

result, _ := fooDivide(5, 4)

In the latter case, the error returned would have been ignored.

Honestly, they’re both pretty similar, except for Rust forcing error checking. Otherwise, there’s little difference, and it’s difficult to find an advantage one has over the other. To my eyes, this is a draw.

I could keep going, digging deeper into other language differences. But the bottom line, from threads, to channels, to generics, Rust provides the developer with more options. In this respect, Rust is closer to C++ than Go. Does this make Rust inherently more complex?

I think so, yes.

So here are my recommendations:

  • Either. If you’re building a web service that handles high load, that you want to be able to scale both vertically and horizontally, either language will suit you perfectly.
  • Go. But if you want to write it faster, perhaps because you have many different services to write, or you have a large team of developers, then Go is your language of choice. Go gives you concurrency as a first-class citizen, and does not tolerate unsafe memory access (neither does Rust), but without forcing you to manage every last detail. Go is fast and powerful, but it avoids bogging the developer down, focusing instead on simplicity and uniformity.
  • Rust. If on the other hand, wringing out every last ounce of performance is a necessity, then Rust should be your choice. Rust is more of a competitor to C++ than it is with Go. Having battled with C++, Rust feels just as powerful but with many happy improvements. Rust empowers developers to have control over every last detail of how their threads behave with the rest of the system, how errors should be handled, and even the lifetime of their variables!
  • Rust. Rust was designed to interoperate with C. Go can as well, but gives up a lot to achieve this goal, and it’s not really its focus.
  • Go. If readability is a requirement, go with Go. It’s far too easy to make your code hard for others to grok with Rust.

I hope you enjoyed reading this!