×

Search anything:

Learn Golang implementation in one article

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article on OpenGenus, we will explore the complete introduction to programming in Go also known as Golang. We will cover basic concepts like data types, functions and others with code snippets and implement Linked List from scratch applying the concepts.

Table of contents:

  1. Introduction
  2. Installation
  3. Programming
    1. Introduction
    2. Executing the Program
    3. Data Types
    4. Variables and Constants
    5. Control Structures
    6. Arrays, Slices and Maps
    7. Functions
    8. Structures,Interfaces and Embedding
    9. Pointers
    10. Recursion
    11. Linked List in Go
  4. Quiz

Introduction

Go is a statically typed and compiled programming language that is designed for efficiency and concurrency. Go was developed by Google and was released in 2012. Go is a high-level programming language and includes built-in memory safety and garbage collection. Some of the main advantages of Go are:

  • Simplicity: Go's syntax is minimalistic and easy to understand.

  • Concurrency: Go provides built-in support for concurrent programming through Go routines and channels.

  • Strong Typing: Go is a statically typed language so that variable types are determined at compile-time.

  • Compilation: Go code is compiled directly to machine code which results in high-performance binaries.

  • Standard Library: Go comes with a rich standard library that covers a wide range of functionality.

Installation

  • Windows: Visit the official website at https://golang.org/dl/ and download the installer for Windows. Choose the MSI installer and follow the on-screen instructions to complete the installation.

  • macOS: Visit the official website at https://golang.org/dl/ and download the installer for macOS. Choose the PKG installer and follow the on-screen instructions to complete the installation.

  • Linux: Use the package manager of your distribution to install Go. For example, on Ubuntu or Debian-based systems, you can run:

sudo apt-get update
sudo apt-get install golang

Open a terminal or command prompt and type the following command to verify that Go is installed:

go version

Programming

Introduction

Let's create a new file named 'main.go' in a directory of your choice to implement the Go programming language. You can use either an IDE or a text editor for this.

Program

package main

import "fmt"

// Comments...

func main() {

 fmt.Println("Hello World")
 
}

Output

Hello World

Explanation

  • package main: Every Go program starts with a package declaration. The main package is the entry point for the program.

  • import "fmt": This line imports the "fmt" package, which provides functions for formatted I/O.

  • // Comments...: Comments in Go are denoted by // for single-line comments and /* */ for multi-line comments.

  • func main(): The main function is the entry point of your program, and it's where the program execution begins. It has no parameters, and its return type is void.

  • fmt.Println("Hello World"): The fmt.Println function is used to print "Hello World" to the console.

  • {}: Braces are used to define code blocks, enclosing functions, control structures, and specifying their scope.

Executing the program

To run the file after saving the changes, open a terminal or command prompt in the same directory as the main.go file, and then type go run main.go. The go run command compiles the file into an executable and then runs the program.

Data Types

  • Numbers: Go splits numbers into two kinds: integers and floating-point numbers. In general, use 'float64' when working with floating-point numbers, and for integers, use 'int' when working with them since it adapts to the machine's architecture.

    • Unsigned integers: uint8, uint16, uint32, uint64
    • Signed integers: int8, int16, int32, int64
    • The numbers (8, 16, 32, and 64) indicate the number of bits each type uses.
    • For floating-point numbers, Go has two types: float32 (single precision) and float64 (double precision).
  • Strings: String literals can be created using double quotes ("") or backticks (``). The length of a string can be found using the len() function. Escape sequences can be used inside strings to represent special characters ("\n" for a newline). Go supports string concatenation using the '+' operator.

  • Boolean: Go uses three logical operators with boolean values.

    • && (AND) : Returns true if both operands are true.
    • || (OR) : Returns true if at least one operand is true.
    • ! (NOT) : Returns the opposite of the operand's boolean value.

Program

package main

import "fmt"

// Data Types

func main() {

fmt.Println("Sum: ", 1 + 1);

fmt.Println("Escape Sequence: \n");

fmt.Println("Length: ", len("String"));

fmt.Println("Alpha " + "Beta");

fmt.Println("Boolean: ", true && false);

}

Output

Sum:  2
Escape Sequence: 

Length:  6
Alpha Beta
Boolean:  false

Explanation

  • Calculates and prints the sum of 1 + 1 (integer addition).

  • Prints the text "Escape Sequence:" followed by an escape sequence \n, which represents a newline character.

  • Calculates and prints the length of the string "String" using the len function.

  • Concatenates the strings "Alpha" and "Beta" using the + operator and prints the result as "Alpha Beta."

  • Performs a logical AND operation (&&) between true and false boolean values and prints the result, which is false.

Variables and Constants

  • var x string = "String": The variables in Go are created using the var keyword, then the variable name, the type and finally assigning a value to the variable.

  • x := "String": The Go compiler can infer type based on the value assigned to the variable.

  • const x string = "String": In Go, constants are variables but heir values cannot be changed later.

  • Go also supports shorthand when defining multiple variables. Use paratheses to define variables after the keyword (var or const).
    var ( a = 5 b = 10 c = 15)

Program

package main

import "fmt"

// Variables and Constants

func main() {

var Int int = 5;

fmt.Println("Int: ", Int);

var Float float64;

Float = 50.5;

fmt.Println("Float: ", Float);

var String string = "Hello"

fmt.Println("String: ", String + " " + "World!");

const Const int64 = 6;

fmt.Println("Const: ", Const);

x := "Hi";

fmt.Println("Type inference: ", x);

var (
a = 5
b = "String"
c = false
)

fmt.Println("Shorthand: ", a, b, c);

}

Output

Int:  5
Float:  50.5
String:  Hello World!
Const:  6
Type inference:  Hi
Shorthand:  5 String false

Explanation

  • Declares an integer variable named Int and initializes it with the value 5.

  • Declares a float64 variable named Float using type inference and assigns the value 50.5 to it.

  • Declares a string variable named String and initializes it with the string "Hello".

  • Declares a constant named Const with the value 6 of type int64.

  • Declares a variable x using the shorthand := with type inference.

  • Declares multiple variables (a, b, and c) and initializes them in a single block using shorthand notation.

Control Structures

  • for: Go uses a for loop to create various types of loops, including traditional for loops, for loops that behave like while loops, and more.

  • if: In Go, the if statement is used for conditional branching, allowing you to execute a block of code if a certain condition is true.

  • switch: In Go, the switch statement is used for conditional branching based on the value of an expression.

  • In Go, semicolons (;) are not required as statement terminators in most cases. However, there are a few cases where you might use semicolons in Go like when multiple statements are on a single line and a for loop with multiple components.

Program

package main

import "fmt"

// Control Structures

func main() {

    i := 1
    
    for i <= 5 {
    
    fmt.Println(i)
    
    i = i + 1
    
    }

    for i := 0; i < 5; i++ {
    
    fmt.Println(i)
    
    }

    age := 25

    if age < 18 {
    
        fmt.Println("Minor")
        
    } else if age >= 18 && age < 65 {
    
        fmt.Println("Adult")
        
    } else {
    
        fmt.Println("Senior Citizen")
        
    }

    day := "Wednesday"

    switch day {
    
    case "Monday":
        fmt.Println("Monday")
    case "Tuesday":
        fmt.Println("Tuesday")
    case "Wednesday":
        fmt.Println("Wednesday")
    default:
        fmt.Println("Weekend day")
        
    }

}

Output

1
2
3
4
5
0
1
2
3
4
Adult
Wednesday

Explanation

  • Uses a for loop to print numbers from 1 to 5.

  • Uses another for loop with a different syntax to print numbers from 0 to 4.

  • Defines an age variable and uses an if statement to determine whether the person is a minor, an adult, or a senior citizen based on their age.

  • Defines a day variable and uses a switch statement to print a message based on the day of the week.

Arrays, Slices and Maps

  • arrays: Array is a fixed-size, ordered collection of elements of the same data type. Arrays in Go have a fixed length, which means you must specify the number of elements they can hold when you declare them.

  • slices: Slices are a more flexible and dynamic alternative to arrays. Unlike arrays, slices are not fixed in size so they can grow or shrink as needed.

  • maps: Map is a built-in data structure used to store key-value pairs.

Program

package main

import "fmt"

// Arrays, Slices and Maps

func main() {

    var numbers [2]int

    numbers[0] = 1
    
    numbers[1] = 2

    fmt.Println(numbers[0])

    fruits := [3]string{"apple", "banana", "cherry"}

    fmt.Println(len(fruits))

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

    slice := arr[1:4]

    fmt.Println(slice[0])

    myMap := make(map[string]int)

    myMap["one"] = 1
    myMap["two"] = 2
    myMap["three"] = 3

    myMap["three"] = 333

    delete(myMap, "three")

    for key, value := range myMap {

        fmt.Printf("Key: %s, Value: %d\n", key, value)

    }

}

Output

1
3
2
Key: one, Value: 1
Key: two, Value: 2

Explanation

  • Declares an array numbers with a length of 2, assigns values to its elements, and prints the value at index 0.

  • Declares an array fruits with three string elements and prints the length of the array, which is 3.

  • Creates a slice slice by taking a portion of the arr array from index 1 to 3 (excluding index 3) and prints the value at index 0 of the slice.

  • Creates a map myMap and adds key-value pairs to it. It then updates the value associated with the key "three" and deletes the key "three" from the map. Finally, it iterates over the map, printing the keys and values.

Functions

  • Functions are a fundamental building block of the language and are used to define reusable blocks of code. Functions can have parameters, return values, and can be called from other parts of the code.

  • A variadic function is a function that can accept a variable number of arguments of the same type.

  • A closure is a function value that references variables from its containing function's scope, even after the outer function has finished execution.

Program

package main

import "fmt"

// Functions

func add(a, b int) int {

    return a + b

}

func divideAndRemainder(a, b int) (int, int) {

    quotient := a / b

    remainder := a % b

    return quotient, remainder

}

func sum(numbers ...int) int {

    total := 0

    for _, num := range numbers {

        total += num

    }

    return total

}

func main() {

    result := add(3, 5)

    fmt.Println("Addition:", result)

    q, r := divideAndRemainder(10, 3)

    fmt.Printf("Quotient: %d, Remainder: %d\n", q, r)

    total := sum(1, 2, 3, 4, 5)

    fmt.Println("Sum result:", total)

    square := func(x int) int {

        return x * x

    }

    num := 6

    squared := square(num)

    fmt.Printf("Square of %d: %d\n", num, squared)

}

Output

Addition: 8
Quotient: 3, Remainder: 1
Sum result: 15
Square of 6: 36

Explanation

  • add: Function takes two integers, adds them, and returns the result.

  • divideAndRemainder: Function takes two integers, performs division, and returns both the quotient and remainder.

  • sum: Function is a variadic function that accepts an arbitrary number of integers and returns their sum.

  • square: A closure named square is defined to calculate the square of an integer. The square closure is used to calculate the square of the number 6, and the result is printed.

Structures,Interfaces and Embedding

  • Structure is a composite data type which groups variables under a single name. They are used to create user-defined data types that can hold different data types.

  • Interface defines a set of methods that a type must implement. Interfaces in Go are implicitly implemented, meaning that there is no need to explicitly declare that a type implements an interface.

  • In Go, Embedding is a way to compose new types by including other types as fields within a struct. It is similar to inheritance in other languages. Go supports struct embedding and interface embedding.

Program

package main

import "fmt"

// Structures,Interfaces and Embedding

type Animal interface {

    Speak() string

    Move() string

}

type Dog struct {

    Name string

}

func (d Dog) Speak() string {

    return "Woof!"

}

func (d Dog) Move() string {

    return "Running on four legs"

}

type Bird interface {

    Chirp() string

}

type Sparrow struct {

    Name string

}

func (s Sparrow) Speak() string {

    return "Chirp!"

}

func (s Sparrow) Move() string {

    return "Flying through the sky"

}

func (s Sparrow) Chirp() string {

    return "Chirp! Chirp!"

}

func main() {

    dog := Dog{Name: "Rover"}

    sparrow := Sparrow{Name: "Tweetie"}

    animal1 := Animal(dog)

    fmt.Println(animal1.Speak())

    fmt.Println(animal1.Move())

    animal2 := Animal(sparrow)

    fmt.Println(animal2.Speak())

    fmt.Println(animal2.Move())

    bird := Bird(sparrow)

    fmt.Println(bird.Chirp())

}

Output

Woof!
Running on four legs
Chirp!
Flying through the sky
Chirp! Chirp!

Explanation

  • Animal: Interface with two methods: Speak() and Move(). This interface represents animals with speaking and moving behaviors.

  • Dog: Struct, which has a Name field and then implements the Speak() and Move() methods for the Dog struct. These methods return strings representing the sound a dog makes and how it moves.

  • Bird: Interface with a single method: Chirp(). This interface represents birds with chirping behavior.

  • Sparrow: Struct, which also has a Name field and then implements the Speak(), Move(), and Chirp() methods for the Sparrow struct. These methods return strings representing how a sparrow speaks, moves, and chirps.

  • main: Function, we create instances of both Dog and Sparrow.

  • The Animal interface to create animal1 and animal2 and directly assign instances of Dog and Sparrow to variables of type Animal. This demonstrates interface embedding and polymorphism. We can call the Speak() and Move() methods on these variables.

  • The Bird interface is used to create the bird variable and assign the Sparrow instance to it and then call the Chirp() method on the bird variable.

  • Print the results of calling various methods on these instances, showing that each type behaves differently based on the methods they've implemented.

  • In this program, the Sparrow struct has no direct mention of the Dog struct, but the Sparrow struct implicitly includes a field of type Dog because of the way it was defined. This is an example of struct embedding.

Pointers

  • A pointer is a variable that stores the memory address of another variable or object in a computer's memory. Pointers in Go are generally safer than in languages like C and C++ because Go has automatic memory management and a strong type system that helps prevent many common pointer-related errors.

  • In Go, you declare a pointer using the * symbol followed by the data type. For example, var ptr *int declares a pointer to an integer. If you declare a pointer without initializing it, it will have a default value of nil. To get the memory address of a variable use the & operator. For example, x := 42; ptr := &x assigns the memory address of the integer variable x to the ptr pointer.

  • The * operator is used to explicitly dereference pointers when accessing the value they point to. The new function creates a new variable of a specified type and return a pointer to that variable.

Program

package main

import "fmt"

// Pointers

func increment(x *int) {

    *x++
    
}

type Person struct {
  
    Name string
    
    Age int
    
}

func one(Ptr *int) {
  
  *Ptr = 1

}

func main() {
  
    var x *int

    y := 10
    
    x = &y

    fmt.Println(*x) 
    
    increment(&y)

    fmt.Println(y) 
    
    pers := Person{"Bob", 26}
 
    Pointer := &pers
 
    fmt.Println(Pointer)

    fmt.Println(Pointer.Name)
 
    fmt.Println((*Pointer).Age)
    
    person := new(Person)

    person.Name = "Alice"
    
    person.Age = 25

    fmt.Println(person.Name, person.Age) 
    
    ptr := new(int)

    one(ptr)
    
    fmt.Println(*ptr)
    
}

Output

10
11
&{Bob 26}
Bob
26
Alice 25
1

Explanation

  • Declares a pointer variable x to an integer and an integer variable y with an initial value of 10.

  • Assigns the memory address of y to the pointer x using the & operator. Now, x points to the memory location where y is stored.

  • Prints the value pointed to by x, which is 10.

  • Call the increment function, passing the address of y to it. This function increments the value of y by one.

  • After the function call, you print the updated value of y, which is 11.

  • The function one takes a pointer to an integer as its parameter and sets the value pointed to by that pointer to 1.

  • Creates a Person struct named pers with the name "Bob" and age 26.

  • Creates a pointer Pointer to the pers struct using &pers.

  • Prints the pointer to the pers struct, which shows the memory address where pers is located.

  • Accesses the Name field of the pers struct through the Pointer pointer and print it, which prints "Bob". Similarly, the program accesses the Age field of the pers struct through the pointer and print it, which prints 26.

  • The new keyword is used to create a new Person struct named person. This allocates memory for the struct and returns a pointer to it and then sets the Name and Age fields of the person struct.

  • The code print the Name and Age fields of the person struct, which prints "Alice 25".

  • The new keyword is used to create an integer pointer ptr using the new(int) function. Finally, the value pointed to by ptr in the main function is printed.

Recursion

  • Recursion like in many programming languages, refers to the practice of a function calling itself. Recursion is a powerful technique used to solve problems that can be broken down into smaller, similar subproblems.

Program

package main

import "fmt"

func gcd(a, b int) int {
  
    if b == 0 {
      
        return a
        
    }
    
    return gcd(b, a%b)
    
}

func main() {
  
    num1, num2 := 48, 18
    
    result := gcd(num1, num2)
    
    fmt.Printf("GCD of %d and %d is %d\n", num1, num2, result)
    
}

Output

GCD of 48 and 18 is 6

Explanation

  • The gcd function takes two integers a and b as input. It uses the Euclidean algorithm for finding the GCD of a and b.

  • The base case of the recursion is when b becomes 0. In this case, the GCD is a, so we return a. Otherwise, the function makes a recursive call with b and a%b (the remainder of a divided by b).

  • This recursive call reduces the problem to a smaller pair of integers. The recursion continues until b becomes 0, and then the GCD is returned.

Linked List in Go

  • A linked list is a data structure in which each element called a "node" contains a data and a reference. Linked lists are a fundamental data structure in computer science and are used to store collections of data.

    • Node: Each element in a linked list is represented by a node. A node contains two parts:

    • Data: Data part holds the actual value or data that you want to store in the linked list.

    • Next: This part is a reference (pointer) to the next node in the sequence.

    • Head: It is the node that marks the beginning of the linked list and serves as the starting point for traversing the list. If the list is empty, the head is set to nil.

  • Linked lists support several operations like insertion, deletion, and searching.

    • Insertion: To insert into the linked list, traverse the list until you reach the last node. Then, create a new node with the desired data and set the next pointer of the last node to point to the new node.

    • Deletion: To delete a node with a specific value,traverse the list while keeping track of the current and previous nodes. Once you find the node with the target value, update the next pointer of the previous node to skip the node to be deleted.

    • Searching: To search for an element with a specific value, start at the head of the linked list and traverse the list until you find a node with the target value.

Program

package main

import "fmt"

// Linked List

type Node struct {
    
    data int
    
    next *Node
    
}

type LinkedList struct {
    
    head *Node
    
}

func (ll *LinkedList) Append(data int) {
    
    newNode := &Node{data, nil}

    if ll.head == nil {
        
        ll.head = newNode
        
        return
        
    }

    current := ll.head
    
    for current.next != nil {
        
        current = current.next
        
    }
    
    current.next = newNode
    
}

func (ll *LinkedList) Display() {
    
    current := ll.head
    
    for current != nil {
        
        fmt.Printf("%d -> ", current.data)
        
        current = current.next
        
    }
    
    fmt.Println("nil")
    
}

func (ll *LinkedList) Search(data int) bool {
    
    current := ll.head
    
    for current != nil {
        
        if current.data == data {
            
            return true
            
        }
        
        current = current.next
        
    }
    
    return false
    
}

func (ll *LinkedList) Delete(data int) {
    
    if ll.head == nil {
        
        return
        
    }

    if ll.head.data == data {
        
        ll.head = ll.head.next
        
        return
        
    }

    current := ll.head
    
    for current.next != nil {
        
        if current.next.data == data {
            
            current.next = current.next.next
            
            return
            
        }
        
        current = current.next
        
    }
    
}

func main() {
    
    list := LinkedList{}

    fmt.Print("Enter the number of elements to create: ")
    
    var numElements int
    
    fmt.Scan(&numElements)
    
    for i := 0; i < numElements; i++ {
        
        fmt.Printf("Enter element %d: ", i+1)
        
        var value int
        
        fmt.Scan(&value)
        
        list.Append(value)
        
    }

    fmt.Print("Enter the element to search: ")
    
    var searchValue int
    
    fmt.Scan(&searchValue)

    if list.Search(searchValue) {
        
        fmt.Printf("%d found in the list.\n", searchValue)
        
    } else {
        
        fmt.Printf("%d not found in the list.\n", searchValue)
        
    }

    fmt.Print("Enter the element to delete: ")
    
    var deleteValue int
    
    fmt.Scan(&deleteValue)

    list.Delete(deleteValue)
    
    fmt.Printf("%d deleted from the list.\n", deleteValue)

    fmt.Println("Linked List after Deletion:")
    
    list.Display()
    
}

Output

Enter the number of elements to create: 5
Enter element 1: 55
Enter element 2: 64
Enter element 3: 82
Enter element 4: 10
Enter element 5: 7
Enter the element to search: 82
82 found in the list.
Enter the element to delete: 7
7 deleted from the list.
Linked List after Deletion:
55 -> 64 -> 82 -> 10 -> nil

Time and Space Complexity

Insertion

Time Complexity   : O(n), where n is the number of elements in the linked list.
Space Complexity  :  O(1). The space complexity for insertion is constant.

Deletion

Time Complexity   : O(n), where n is the number of elements in the linked list.
Space Complexity  : O(1). The space complexity for deletion is constant.

Searching

Time Complexity   : O(n), where n is the number of elements in the linked list.
Space Complexity  :  O(1). The space complexity for searching is constant.

Explanation

  • Node struct: Represents a single node in the linked list. Each node has an integer data field (data) and a pointer to the next node (next).

  • LinkedList struct: Represents the linked list itself. It has a pointer to the head node (head), which is the first element of the list.

  • Append(data int): Adds a new node with the specified integer data to the end of the linked list.

  • ll *LinkedList: This is the method receiver and specifies that the following function is a method of the LinkedList type. It is written with parentheses around consists of two parts:

    • ll: This is a short name for the receiver variable and ll stands for "linked list". It is defines by the user.
    • LinkedList: This specifies the receiver's type. It indicates that the method can be called on a value of type LinkedList or a pointer to LinkedList. The * indicates that it can be called on a pointer to the LinkedList type.
  • Display(): Displays the elements of the linked list from the head to the end.

  • Search(data int) bool: Searches for a node with the specified data in the linked list and returns true if found, otherwise false.

  • Delete(data int): Deletes the first occurrence of a node with the specified data from the linked list.

  • main function:

    • It creates an empty linked list and reads the number of elements to create in the linked list from the user.
    • Reads and appends the specified number of elements to the linked list and searches for a specified element in the linked list and prints whether it was found or not.
    • Deletes a specified element from the linked list. Finally, it displays the modified linked list.

Quiz

Question 1

Which of the following is a valid variable declaration in Go?

All of the above
var x string = "String"
x := "String"
const x string = "String"
var x string = "String": The variables in Go are created using the var keyword, then the variable name, the type and finally assigning a value to the variable. x := "String": The Go compiler can infer type based on the value assigned to the variable. const x string = "String": In Go, constants are variables but heir values cannot be changed later.

Question 2

Does Go support concurrency?

True
False
Go is a statically typed and compiled programming language that is designed for efficiency and concurrency.

MATHANKUMAR V

Mathankumar V is the Winner of Smart India Hackathon (2022) and Software Developer, Intern at OpenGenus. He is pursuing BE in Computer Science from Dr. Mahalingam College of Engineering and Technology

Read More

Improved & Reviewed by:


Ue Kiao, PhD Ue Kiao, PhD
Aditya Chatterjee Aditya Chatterjee
Learn Golang implementation in one article
Share this