Go Essentials

Go Essentials

Go Essentials

Constructs of Go Lang

Constructs of Go Lang

The Go compiler provides tools or commands for interacting with Go code. Let's take a look at them in this section.

Go language syntax

Package Declaration

Every Go file belongs to a package and must start with a package declaration. The package declaration determines whether the code in that file will be part of an executable or a library. For example:

package main // For executable files

package mypackage // For library files

Importing Packages

To use functionality from other packages, you need to import them. Import statements are typically placed at the beginning of the file after the package declaration. For example:

package main

import (
    "fmt"
    "math"
)

Function Declarations

Functions in Go are defined using the func keyword. The basic syntax for a function declaration is as follows:

func functionName(parameter1 type1, parameter2 type2) returnType {

    // Function body

    return result

}

Control Structures

Go provides standard control structures, such as ifforswitch, and select, which we will cover later. The syntax for these control structures is similar to other C-like languages.

Comments

Go supports both single-line and multi-line comments. Single-line comments start with //, while multi-line comments are enclosed within /* */. For example:

// This is a single-line comment

/*

   This is a

   multi-line comment

*/

Adding visibility to identifiers

Identifiers include variable names, custom data types, functions, and other constructs in Go. When writing modular Go code (we will see what that means later. Go uses capitalization to determine if a package-level identifier is visible outside of the package where it is declared. An identifier whose Name starts with an uppercase letter is exported. Conversely, an identifier whose Name begins with a lowercase letter or underscore can only be accessed from within the package where it is declared.

var Name string // can be accessed anywhere in the codebase.

var localName string // can only be accessed in the source file it is declared in.

Note that Go developers use camel case for naming identifiers instead of snake case, as in Python or Rust.

The go Command

The Go command is a fundamental tool in Go that serves various purposes, including compiling and running Go programs, managing packages, and performing various development tasks. Here are some common go commands:

  • go build: Compiles the Go program and generates an executable binary. If there are no errors, this will create an executable file with the same name as the directory.

  • go run: Compiles and runs a Go program in a single step. This is useful for quickly testing small programs.

  • go install: Compiles and installs the Go package or program. If the package is a command (an executable), it will be placed in the bin directory defined in your GOPATH.

  • go get: Fetches and installs packages from the remote repository.

  • go test: Runs tests associated with the current package.

For more details and a full list of go commands, you can execute go help or go help < Command> in your terminal. However, we will use some of them in the Milestone Project section in this guide.

Getting Third-Party Go Tools

Go is an open-source language. This means that the Go community has developed a plethora of third-party tools that enhance the Go development experience. To get these tools, you can use the go get Command followed by the URL or import path of the tool.

For example:

go get github.com/golangci/golangci-lint/cmd/golangci-lint

This Command will download and install the golangci-lint tool, a popular static code analysis tool for Go.

Staying Up to Date

To stay up to date with the latest changes and improvements, you should keep your Go installation updated. Fortunately, updating Go is straightforward:

  • First, you can check if a new version is available by visiting the Go website or using the Go version command.

  • If there is a new version, download the installer for your operating system from the official Go website and run it.

  • The installer will detect your current Go installation and perform the update.

I'd like to point out that updating your Go environment periodically is essential to take advantage of bug fixes, performance improvements, and new features introduced in the latest versions.

Variable and Constant Declaration

In Go, you declare variables and constants explicitly, indicating their types. This strong typing helps ensure type safety and clarity in code. Let's explore how to declare and use variables and constants in Go:

Variable Declaration

To declare a variable, use the var keyword followed by the variable name, its type, and an optional initial value. If you don't specify the value, the Go compiler will initialize it to the zero value of that variable type. You can make a short assignment declaration if you declare the variable in a function. When you do so, the Go compiler assumes the variable type, allowing you only to specify the variable Name and the value it stores. For example:

package main
import "fmt"

func main() {

    var name string // initialized as an empty string:""

    name = "John"// name string now becomes "John"

    fmt.println("Name:", name) // Output: Name: John

    var age int = 30

    fmt.Println("Age:", age) // Output: Age: 30

    // You can also use the short variable declaration syntax

    City := "New York"

    fmt.Println("City:", city) // Output: City: New York

}

In a backend system, you often need to work with different data types. You declare variables explicitly, indicating their types for clarity and type safety.

package main

import "fmt"

func main() {
    var databaseURL string
    databaseURL = "mongodb://localhost:27017/mydb"
    fmt.Println("Database URL:", databaseURL)

    var port int = 8080
    fmt.Println("Port:", port)

    // Using the short variable declaration syntax
    serverName := "Backend Server"
    fmt.Println("Server Name:", serverName)
}

Multiple Variable Declaration

Go allows you to declare multiple variables in a single statement. You can do variable declaration in two ways and in both local and global scopes. You can also do a short assignment declaration with multiple variables.

Software systems frequently deal with multiple variables simultaneously, especially while initializing settings or configurations.

package main

import "fmt"

func main() {
    var (
        maxConnections int = 100
        timeoutSeconds int = 30
    )

    fmt.Println("Max Connections:", maxConnections)
    fmt.Println("Timeout Seconds:", timeoutSeconds)
}

Constant Declaration

To declare a constant, use the const keyword followed by the constant Name, its type (optional), and the constant's value. Constants are preferably declared globally (outside of functions) but can be declared globally. Unlike variables, constants must be initialized at the time of declaration and cannot be changed later.

In a backend system, you might have fixed values that remain constant throughout the program's execution. Declare these as constants.

package main

import "fmt"

func main() {
    const (
        MaxRetries  = 3
        BufferSize  = 1024
        RequestType = "POST"
    )

    fmt.Println("Max Retries:", MaxRetries)
    fmt.Println("Buffer Size:", BufferSize)
    fmt.Println("Request Type:", RequestType)
}

In software engineering, it is common to see port numbers and environment variables declared as constants.

Enumerated Constants

Go also supports enumerated constants using the iota keyword. Enumerated constants are auto-incremented integer values commonly used to define a set of related named constants. For example, say we have a backend system that allows users to subscribe to services; here is what our subscription model will look like:

package main

import "fmt"

func main() {
    const (
        Basic = iota  // 0
        Premium       // 1 (automatically incremented from iota)
        Gold          // 2 (automatically incremented from iota)
        Enterprise    // 3 (automatically incremented from iota)
    )

    fmt.Println("Available subscription packages and index:")
    fmt.Println("Basic:", Basic)
    fmt.Println("Premium:", Premium)
    fmt.Println("Gold:", Gold)
    fmt.Println("Enterprise:", Enterprise)
}

In this example, the iota keyword creates a series of integer values.

Determining and using variables and constants is essential for writing effective and maintainable Go code. Following the explicit type declaration approach can make your code more robust and easier to understand, especially in large projects.

Data Types and Composite Types

Go provides a range of built-in and composite data types, making working with data in different scenarios easy.

Primitive Data Types

Go offers several primitive data types that represent basic values. Here are some commonly used primitive data types in day-to-day Go programming:

Integers

Used for representing whole numbers. Depending on the architecture, you have int and uint types with different sizes, such as int8, int16, int32, int64, uint8, uint16, uint32, and uint64.

package main

import "fmt"

func main() {
    var userID int64 = 12345
    fmt.Println("User ID:", userID)

    var requestCount uint32 = 100
    fmt.Println("Request Count:", requestCount)
}

Floating-Point Numbers

Used for representing decimal numbers. You have float32 and float64 data types.

package main

import "fmt"

func main() {
    var pi float64 = 3.14159
    fmt.Println("Value of Pi:", pi)
}

Strings

Used for representing text and characters.

package main

import "fmt"

func main() {
    username := "john_doe"
    fmt.Println("Username:", username)
}

Boolean

Used for representing true/false values.

package main

import "fmt"

func main() {
    isLoggedIn := true
    fmt.Println("Logged in?", isLoggedIn)
}

Composite Types

Go provides composite types that allow you to group multiple values together.

Arrays

Fixed-size collections of elements of the same type.

package main

import "fmt"

func main() {
    var numbers [5]int
    numbers = [5]int{1, 2, 3, 4, 5}

    fmt.Println("Numbers:", numbers) // Output: Numbers: [1 2 3 4 5]
}

Slices

Dynamic and flexible views of underlying arrays.

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}

    fmt.Println("Numbers:", numbers) // Output: Numbers: [1 2 3 4 5]
}

Maps

Unordered collections of key-value pairs.

package main

import "fmt"

func main() {
    userAge := map[string]int{
        "John": 30,
        "Jane": 25,
    }

    fmt.Println("User Ages:", userAge) // Output: User Ages: map[Jane:25 John:30]
}

Structs

Custom data types with named fields that group related data.

package main

import "fmt"

type User struct {
    ID       int
    Name     string
    Email    string
    IsActive bool
}

func main() {
    user := User{ID: 1, Name: "John Doe", Email: "[email protected]", IsActive: true}

    fmt.Println("User:", user)         // Output: User: {1 John Doe [email protected] true}
    fmt.Println("User Name:", user.Name) // Output: User Name: John Doe
}

It is important to familiarize yourself with Maps, Structs, and Slices, as they are frequently used in software engineering.

Control Structures

Software systems use control structures to make decisions and control the code flow. Go provides several control structures to handle different scenarios efficiently. Let's explore these control structures with relevant examples.

If and Else

The if and else statements allow you to perform conditional execution in your code.

package main

import "fmt"

func main() {
    age := 30

    if age >= 18 {
        fmt.Println("You are an adult.")
    } else {
        fmt.Println("You are a minor.")
    }
}

For Loops

Go offers four types of loop, each serving a specific purpose in backend development.

Classic For Loop

The classic for loop allows you to iterate over a range of values.

package main

import "fmt"

func main() {
    for i := 1; i <= 5; i++ {
        fmt.Println("Iteration:", i)
    }
}

For Loop with a Single Condition

This type of for loop acts like a while loop, where the loop continues as long as the condition is true.

package main

import "fmt"

func main() {
    i := 1

    for i <= 5 {
        fmt.Println("Iteration:", i)
        i++
    }
}

For Loop with Range

A for loop with range is commonly used to iterate over elements of an array, slice, map, or string.

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}

    for index, value := range numbers {
        fmt.Printf("Index: %d, Value: %d\\n", index, value)
    }
}

Infinite Loop

An infinite loop continues indefinitely until it encounters a break statement or exits the program.

package main

import "fmt"

func main() {
    i := 1

    for {
        fmt.Println("Infinite Loop:", i)
        i++

        if i > 5 {
            break
        }
    }
}

The for loop with range keyword is usually used in software engineering, as well as the complete style for loop.

Switch and Case

The switch statement allows you to create multi-way conditionals in your backend code.

package main

import "fmt"

func main() {
    day := "Sunday"

    switch day {
    case "Monday":
        fmt.Println("It's the start of the week.")
    case "Friday":
        fmt.Println("It's the end of the workweek.")
    case "Saturday", "Sunday":
        fmt.Println("It's the weekend.")
    default:
        fmt.Println("It's a regular weekday.")
    }
}

Whenever you're ready

There are 4 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Get Backend Jobs

Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board