Hi, my name is Walid, a backend developer who’s currently learning Go and sharing my journey by writing about it along the way.
Resource :

  • The Go Programming Language book by Alan A. A. Donovan & Brian W. Kernighan
  • Matt Holiday go course

Go is a statically typed language that provides a powerful and expressive type system, precise package initialization rules, native support for complex numbers, efficient handling of UTF-8, and a sophisticated constant generator known as iota. Understanding these concepts in depth will help you write robust and efficient Go programs.

Type Declarations in Go

In Go, the type keyword allows developers to define new types based on existing ones. This enables better code organization, improved readability, and stricter type safety by preventing unintended type mixing.

Defining Custom Types

type Age int // Defines a new type `Age` as an alias for `int`
var myAge Age = 25

Although Age is based on int, Go treats it as a separate type, meaning it cannot be used interchangeably with int without explicit conversion:

var years int = 30
myAge = Age(years) // Explicit conversion is required

Struct Type Declaration

Structs are composite types that allow grouping multiple fields together.

type Person struct {
    Name string
    Age  int
}

This enables the creation of structured data models with meaningful field names.

Type Aliases vs. Custom Types

Introduced in Go 1.9, type aliases allow an existing type to be referred to by another name without creating a distinct type.

type MyInt = int // `MyInt` is an alias for `int`, not a new type

Unlike Age (a custom type), MyInt behaves exactly like int with no additional type safety.

Package Initialization

Package-level variables in Go are initialized in the order they are declared, ensuring deterministic behavior.

Initialization Order

var x = y + 2 // `y` must be initialized before `x`
var y = 10

Go guarantees that y is initialized before x, preventing undefined behavior.

The init Function

In addition to package-level variable initialization, Go provides an init function that executes automatically when the package is loaded.

func init() {
    fmt.Println("Package initialized")
}
  • The init function is called once per package.
  • Multiple init functions within a package execute in the order they appear.
  • Dependencies are resolved before execution, ensuring safe initialization across packages.

Basic Data Types in Go

Go's built-in types include:

  • Boolean: bool (values: true or false)
  • Integers: int, int8, int16, int32, int64
  • Unsigned Integers: uint, uint8, uint16, uint32, uint64
  • Floating-Point Numbers: float32, float64
  • Complex Numbers: complex64, complex128
  • Strings: UTF-8 encoded sequences of bytes

Type Size Considerations

Unlike C, Go’s int and uint types are platform-dependent:

  • On 32-bit systems: int is 32 bits
  • On 64-bit systems: int is 64 bits

Complex Numbers in Go

Go natively supports complex numbers using complex64 and complex128.

Creating Complex Numbers

var c1 complex64 = 1 + 2i
c2 := complex(3, 4) // Using the built-in `complex` function
fmt.Println(c1, c2) // Output: (1+2i) (3+4i)

Extracting Real and Imaginary Parts

fmt.Println(real(c2)) // 3
fmt.Println(imag(c2)) // 4

Complex Arithmetic

c3 := c1 + c2
c4 := c1 * c2
fmt.Println(c3, c4)

This makes Go ideal for scientific computing and signal processing.

UTF-8 and Strings

Go uses UTF-8 encoded strings by default, ensuring efficient and flexible text handling.

String Length and Runes

s := "Hello, 世界"
fmt.Println(len(s))        // Outputs number of bytes, not characters
fmt.Println([]rune(s))     // Converts string to runes
fmt.Println(string(s[7:])) // Slices work at the byte level

Go strings are immutable, meaning operations that modify strings return new copies.

Working with Unicode

The unicode package provides utilities for character classification and transformation.

import "unicode"
fmt.Println(unicode.IsDigit('5')) // true
fmt.Println(unicode.IsLetter('A')) // true

The Constant Generator iota

iota is a unique identifier used for defining incrementing constants efficiently. It is often used for enumerations.

Simple iota Example

const (
    A = iota // 0
    B        // 1
    C        // 2
)

Each successive constant increases by one.

Custom Increments

const (
    KB = 1 << (10 * iota) // 1024
    MB                    // 1048576
    GB                    // 1073741824
    TB                    // 1099511627776
)

Here, iota generates bit-shifted values representing storage sizes.

Using iota with Bit Flags

const (
    Read  = 1 << iota // 1
    Write             // 2
    Exec              // 4
)

This is useful for defining permission masks and other bitwise configurations.

Conclusion

Go's type system, initialization rules, built-in support for complex numbers, UTF-8 handling, and iota make it a powerful and expressive language. Understanding these fundamental concepts allows developers to write more efficient, type-safe, and readable code. Whether you're dealing with large-scale data processing, low-level system programming, or high-performance computing, Go's design ensures clarity and maintainability.