Go

Essential Go syntax, data structures, and patterns for building efficient and concurrent applications.

languages
gogolangbackendconcurrency

Hello World

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

Variables

// Variable declaration
var name string = "Go"
var age int = 10

// Short declaration (type inference)
language := "Go"
version := 1.21

// Multiple declarations
var x, y, z int = 1, 2, 3
a, b, c := "hello", 42, true

// Constants
const Pi = 3.14159
const (
    StatusOK    = 200
    StatusError = 500
)

Data Types

// Basic types
var b bool = true
var s string = "hello"
var i int = 42           // int, int8, int16, int32, int64
var u uint = 42          // uint, uint8, uint16, uint32, uint64
var f float64 = 3.14     // float32, float64
var c complex128 = 1+2i  // complex64, complex128
var by byte = 255        // alias for uint8
var r rune = 'A'         // alias for int32 (Unicode code point)

// Zero values
var defaultInt int       // 0
var defaultStr string    // ""
var defaultBool bool     // false

Arrays and Slices

// Arrays (fixed size)
var arr [5]int = [5]int{1, 2, 3, 4, 5}
arr2 := [...]int{1, 2, 3}  // compiler counts elements

// Slices (dynamic size)
slice := []int{1, 2, 3, 4, 5}
slice2 := make([]int, 5)      // length 5
slice3 := make([]int, 5, 10)  // length 5, capacity 10

// Slice operations
slice = append(slice, 6, 7)   // append elements
sub := slice[1:4]             // slice from index 1 to 3
length := len(slice)          // length
capacity := cap(slice)        // capacity

// Copy slice
dest := make([]int, len(slice))
copy(dest, slice)

Maps

// Create a map
m := make(map[string]int)
m["one"] = 1
m["two"] = 2

// Map literal
scores := map[string]int{
    "Alice": 95,
    "Bob":   87,
}

// Access and check existence
value := scores["Alice"]
value, exists := scores["Alice"]
if exists {
    fmt.Println(value)
}

// Delete a key
delete(scores, "Bob")

// Iterate over map
for key, value := range scores {
    fmt.Printf("%s: %d\n", key, value)
}

Control Flow

// If statement
if x > 10 {
    fmt.Println("greater")
} else if x < 10 {
    fmt.Println("less")
} else {
    fmt.Println("equal")
}

// If with initialization
if val := compute(); val > 0 {
    fmt.Println(val)
}

// Switch statement
switch day {
case "Monday":
    fmt.Println("Start of week")
case "Friday":
    fmt.Println("End of week")
default:
    fmt.Println("Midweek")
}

// Switch without condition
switch {
case x < 0:
    fmt.Println("negative")
case x > 0:
    fmt.Println("positive")
default:
    fmt.Println("zero")
}

Loops

// Basic for loop
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

// While-style loop
for x < 100 {
    x *= 2
}

// Infinite loop
for {
    // break to exit
    break
}

// Range over slice
nums := []int{1, 2, 3}
for index, value := range nums {
    fmt.Printf("%d: %d\n", index, value)
}

// Range over map
for key, value := range myMap {
    fmt.Printf("%s: %v\n", key, value)
}

// Range over string (runes)
for i, char := range "hello" {
    fmt.Printf("%d: %c\n", i, char)
}

Functions

// Basic function
func add(a int, b int) int {
    return a + b
}

// Multiple return values
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

// Named return values
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return  // naked return
}

// Variadic function
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

// Anonymous function / closure
square := func(x int) int {
    return x * x
}

Structs

// Define a struct
type Person struct {
    Name string
    Age  int
}

// Create instances
p1 := Person{Name: "Alice", Age: 30}
p2 := Person{"Bob", 25}  // positional
var p3 Person            // zero value

// Access fields
fmt.Println(p1.Name)
p1.Age = 31

// Pointer to struct
p := &Person{Name: "Charlie", Age: 35}
p.Name = "Charles"  // automatic dereferencing

// Embedded struct (composition)
type Employee struct {
    Person  // embedded
    Title string
}

emp := Employee{
    Person: Person{Name: "Dave", Age: 40},
    Title:  "Engineer",
}
fmt.Println(emp.Name)  // access embedded field

Methods

type Rectangle struct {
    Width, Height float64
}

// Value receiver
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// Pointer receiver (can modify the struct)
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

// Usage
rect := Rectangle{10, 5}
fmt.Println(rect.Area())  // 50
rect.Scale(2)
fmt.Println(rect.Area())  // 200

Interfaces

// Define an interface
type Shape interface {
    Area() float64
    Perimeter() float64
}

// Implement interface (implicit)
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

// Use interface
func printShape(s Shape) {
    fmt.Printf("Area: %.2f\n", s.Area())
}

// Empty interface (any type)
var any interface{}
any = 42
any = "hello"

// Type assertion
str, ok := any.(string)
if ok {
    fmt.Println(str)
}

// Type switch
switch v := any.(type) {
case int:
    fmt.Println("int:", v)
case string:
    fmt.Println("string:", v)
default:
    fmt.Println("unknown type")
}

Error Handling

// Return error
func readFile(path string) ([]byte, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("failed to read file: %w", err)
    }
    return data, nil
}

// Handle error
data, err := readFile("config.json")
if err != nil {
    log.Fatal(err)
}

// Custom error type
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

// Panic and recover
func safeDivide(a, b int) (result int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
            result = 0
        }
    }()
    return a / b  // panics if b is 0
}

Goroutines

// Start a goroutine
go func() {
    fmt.Println("Running in goroutine")
}()

// Goroutine with function
func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

go worker(1)
go worker(2)

// Wait for goroutines
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        worker(id)
    }(i)
}
wg.Wait()

Channels

// Create channel
ch := make(chan int)        // unbuffered
ch := make(chan int, 10)    // buffered with capacity 10

// Send and receive
ch <- 42        // send
value := <-ch   // receive

// Close channel
close(ch)

// Receive with ok check
value, ok := <-ch
if !ok {
    fmt.Println("Channel closed")
}

// Range over channel
for value := range ch {
    fmt.Println(value)
}

// Select statement
select {
case msg := <-ch1:
    fmt.Println("Received from ch1:", msg)
case msg := <-ch2:
    fmt.Println("Received from ch2:", msg)
case ch3 <- 42:
    fmt.Println("Sent to ch3")
case <-time.After(time.Second):
    fmt.Println("Timeout")
default:
    fmt.Println("No communication")
}

Defer

// Defer execution until function returns
func readFile() {
    file, err := os.Open("file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()  // executed when function returns

    // work with file...
}

// Multiple defers (LIFO order)
func example() {
    defer fmt.Println("first")
    defer fmt.Println("second")
    defer fmt.Println("third")
    // Output: third, second, first
}

Pointers

// Declare pointer
var p *int

// Get address
x := 42
p = &x

// Dereference
fmt.Println(*p)  // 42
*p = 100         // x is now 100

// New function
p := new(int)    // allocates zeroed int, returns pointer
*p = 42

// Pointers with functions
func increment(x *int) {
    *x++
}

val := 10
increment(&val)
fmt.Println(val)  // 11

Packages and Imports

// Single import
import "fmt"

// Multiple imports
import (
    "fmt"
    "os"
    "strings"
)

// Aliased import
import (
    f "fmt"
    . "math"  // dot import (use without prefix)
    _ "image/png"  // blank import (side effects only)
)

// Exported names (capitalized)
func PublicFunction() {}   // exported
func privateFunction() {}  // not exported

Common Standard Library

// Strings
import "strings"
strings.Contains("hello", "ell")     // true
strings.Split("a,b,c", ",")          // ["a", "b", "c"]
strings.Join([]string{"a", "b"}, "-") // "a-b"
strings.ToUpper("hello")             // "HELLO"
strings.TrimSpace("  hello  ")       // "hello"

// String formatting
import "fmt"
fmt.Sprintf("Name: %s, Age: %d", name, age)
fmt.Printf("Value: %v, Type: %T\n", val, val)

// JSON
import "encoding/json"
data, _ := json.Marshal(obj)           // struct to JSON
json.Unmarshal(data, &obj)             // JSON to struct

// HTTP
import "net/http"
resp, err := http.Get("https://api.example.com")
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)

// Time
import "time"
now := time.Now()
time.Sleep(time.Second * 2)
formatted := now.Format("2006-01-02 15:04:05")