---
title: "Go"
description: "Go is a statically typed, compiled programming language designed for simplicity, efficiency, and concurrent programming. It's ideal for building fast, scalable server applications and system tools."
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/cheatsheets/go
---

# Go

Go is a statically typed, compiled programming language designed with simplicity and efficiency in mind. It excels at concurrent programming, which makes it a good fit for fast, scalable server applications and system tools.

The sections below cover Go syntax, functions, concurrency patterns, and best practices.

## Getting Started

Fundamental Go concepts and basic syntax for beginners.

### Hello World

Basic Go program structure with package declaration and main function.

**Keywords:** hello world, package, imports, main, output

#### Simple Hello World

```go
package main

import "fmt"

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

_exec_
```go
go run main.go
```

_output_
```go
Hello, World!
```

A basic Go program with package declaration, import, and main function that prints a greeting.

- Every Go program must have a main package and main function.
- The main function is the entry point of the program.

#### Multiple imports

```go
package main

import (
  "fmt"
  "math"
)

func main() {
  fmt.Println("Pi is approximately", math.Pi)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Pi is approximately 3.141592653589793
```

Demonstrates grouped imports using parentheses for multiple packages.

- Use parentheses to group multiple imports.
- Import order doesn't matter, but groups are conventional.

#### Using a custom function

```go
package main

import "fmt"

func greet(name string) {
  fmt.Println("Hello,", name)
}

func main() {
  greet("Gopher")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Hello, Gopher
```

Demonstrates defining and calling a simple function within the main package.

- Functions are declared with the func keyword.
- Function parameters must include their type.

**Best practices:**

- Use fmt.Println for basic output in Go programs.
- Keep the main function minimal and delegate to other functions.
- Always include proper package and import declarations.

**Common errors:**

- **Missing main function**: Every executable Go program must have a main() function in the main package.
- **Incorrect import syntax**: Use "fmt" with double quotes, and group imports in parentheses.

### Variables

Declaring and working with variables in Go, including type inference and shorthand syntax.

**Keywords:** variables, var, declaration, type inference, shorthand

#### Variable declaration with var

```go
package main

import "fmt"

func main() {
  var name string = "Alice"
  var age int = 30
  fmt.Println(name, age)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Alice 30
```

Demonstrates explicit variable declaration with type specification.

- var keyword declares a variable with explicit type.
- Variables must be used after declaration or compilation fails.

#### Type inference

```go
package main

import "fmt"

func main() {
  var name = "Bob"
  var count = 5
  fmt.Println(name, count)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Bob 5
```

Go infers the type from the assigned value without explicit type specification.

- Type inference makes code cleaner when the type is obvious.
- Go still enforces strict typing at compile time.

#### Short declaration operator

```go
package main

import "fmt"

func main() {
  name := "Charlie"
  age := 25
  city := "New York"
  fmt.Println(name, age, city)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Charlie 25 New York
```

Uses the shorthand := operator for quick variable declaration and initialization.

- ':=' is only available inside functions, not at package level.
- Cannot use := if variable already exists.

**Best practices:**

- Use := for short declarations inside functions.
- Use var for package-level variables.
- Use type inference when the type is obvious from context.

**Common errors:**

- **Using := at package level**: Use var instead of := for package-level variables.
- **'Unused variable' compilation error**: Either use the variable or remove it; Go requires all variables to be used.

**Advanced notes:**

- **Multiple Assignment:** Go supports multiple assignment: a, b := 1, "hello"
- **Blank Identifier:** Use _ to ignore values in multi-value returns: _, err := someFunc()

### Constants

Defining constants with const keyword, typed/untyped constants, and iota enumeration.

**Keywords:** constants, const, iota, typed, untyped

#### Simple constants

```go
package main

import "fmt"

const (
  Pi = 3.14159
  MaxRetries = 3
)

func main() {
  fmt.Println("Pi:", Pi)
  fmt.Println("Max retries:", MaxRetries)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Pi: 3.14159
Max retries: 3
```

Declares constants in a grouped block using const.

- Constants must be assigned at compile time.
- Constants cannot be changed after creation.

#### Typed constants

```go
package main

import "fmt"

const (
  Status string = "active"
  Count int = 10
)

func main() {
  fmt.Println(Status, Count)
}
```

_exec_
```go
go run main.go
```

_output_
```go
active 10
```

Demonstrates typed constants with explicit type specification.

- Typed constants are more restrictive but explicit.
- Untyped constants are more flexible for operations.

#### Iota enumeration

```go
package main

import "fmt"

const (
  Sunday iota
  Monday
  Tuesday
  Wednesday
)

func main() {
  fmt.Println("Monday is:", Monday)
  fmt.Println("Wednesday is:", Wednesday)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Monday is: 1
Wednesday is: 3
```

Uses iota to create enum-like constants that auto-increment from 0.

- iota starts at 0 and increments for each const line.
- Perfect for creating enum-like types in Go.

**Best practices:**

- Use constants for fixed values that shouldn't change.
- Use iota for creating enumerations.
- Consider grouping related constants in const blocks.

**Common errors:**

- **Trying to reassign a constant**: Constants are immutable; declare a variable instead.
- **iota not starting at expected value**: Remember iota starts at 0; use expressions like iota+1 if needed.

**Advanced notes:**

- **Iota with expressions:** You can use expressions with iota: const Byte = 1 << (10 * iota)
- **Constant expressions:** Constants can be part of expressions evaluated at compile time.

## Data Types

Go's type system, including basic types, arrays, slices, and pointers.

### Basic Types

Strings, integers, floats, booleans, bytes, and other numeric types.

**Keywords:** string, int, float, bool, byte, rune

#### Numeric types

```go
package main

import "fmt"

func main() {
  var intVal int = 42
  var floatVal float64 = 3.14
  var complexVal complex128 = 1 + 2i

  fmt.Println("Int:", intVal)
  fmt.Println("Float:", floatVal)
  fmt.Println("Complex:", complexVal)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Int: 42
Float: 3.14
Complex: (1+2i)
```

Demonstrates various numeric types including integers, floats, and complex numbers.

- Use int for most integer operations.
- float64 is the default floating-point type.
- complex128 supports complex number operations.

#### String and character types

```go
package main

import "fmt"

func main() {
  var str string = "Hello, Go!"
  var char rune = 'A'
  var byteVal byte = 65

  fmt.Println("String:", str)
  fmt.Println("Rune:", char)
  fmt.Println("Byte:", byteVal)
}
```

_exec_
```go
go run main.go
```

_output_
```go
String: Hello, Go!
Rune: 65
Byte: 65
```

Shows string, rune (Unicode), and byte types in Go.

- Strings are immutable sequences of UTF-8 bytes.
- rune represents a Unicode code point.
- byte is an alias for uint8.

#### Boolean type

```go
package main

import "fmt"

func main() {
  var isActive bool = true
  var isEmpty bool = false

  fmt.Println("Active:", isActive)
  fmt.Println("Empty:", isEmpty)
  fmt.Println("Not empty:", !isEmpty)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Active: true
Empty: false
Not empty: true
```

Demonstrates the boolean type with logical operations.

- bool can only be true or false.
- Use ! for logical NOT operation.

**Best practices:**

- Use int for most integer operations unless size matters.
- Use float64 for floating-point arithmetic.
- Always be explicit about types when needed for clarity.

**Common errors:**

- **Cannot mix types in operations**: Convert types explicitly using type(value) syntax.
- **String index returns byte, not rune**: Convert string to []rune for proper Unicode handling.

### Arrays and Slices

Fixed-size arrays, dynamic slices, and slice operations.

**Keywords:** array, slice, make, append, length, capacity

#### Array declaration

```go
package main

import "fmt"

func main() {
  var arr [3]int = [3]int{1, 2, 3}
  arr2 := [...]string{"a", "b", "c"}

  fmt.Println("Array 1:", arr)
  fmt.Println("Array 2:", arr2)
  fmt.Println("Length:", len(arr))
}
```

_exec_
```go
go run main.go
```

_output_
```go
Array 1: [1 2 3]
Array 2: [a b c]
Length: 3
```

Shows fixed-size array declaration and initialization.

- Arrays have a fixed size specified at compile time.
- Use ... to let the compiler infer array size from initialization.

#### Slice creation and manipulation

```go
package main

import "fmt"

func main() {
  slice := []int{1, 2, 3, 4, 5}
  fmt.Println("Original:", slice)

  slice = append(slice, 6)
  fmt.Println("After append:", slice)

  subSlice := slice[1:4]
  fmt.Println("Sub-slice [1:4]:", subSlice)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Original: [1 2 3 4 5]
After append: [1 2 3 4 5 6]
Sub-slice [1:4]: [2 3 4]
```

Demonstrates dynamic slices with append and slicing operations.

- Slices are dynamic and can grow with append.
- Slicing is done with [start:end] (end is exclusive).

#### Make and capacity

```go
package main

import "fmt"

func main() {
  slice := make([]int, 0, 10)
  fmt.Println("Length:", len(slice), "Capacity:", cap(slice))

  for i := 0; i < 5; i++ {
    slice = append(slice, i)
  }
  fmt.Println("After append:", slice)
  fmt.Println("New length:", len(slice), "Capacity:", cap(slice))
}
```

_exec_
```go
go run main.go
```

_output_
```go
Length: 0 Capacity: 10
After append: [0 1 2 3 4]
New length: 5 Capacity: 10
```

Shows how to create slices with specific capacity using make.

- make creates a slice with length and optional capacity.
- Setting capacity up front avoids reallocations as the slice grows.

**Best practices:**

- Use slices instead of arrays unless size must be fixed.
- Pre-allocate slice capacity with make for better performance.
- Remember that slicing with [start:end] doesn't include the end index.

**Common errors:**

- **Index out of range**: Check slice length with len() before accessing elements.
- **Modifying slice affects original array**: Remember slices are views into arrays; copy if you need independence.

**Advanced notes:**

- **Slice headers:** Slices contain a pointer, length, and capacity internally.
- **Copy function:** Use copy(dest, src) to copy slice elements without sharing backing array.

### Pointers

Pointer declaration, address operator, and dereferencing.

**Keywords:** pointer, address, dereference, nil, 

#### Pointer basics

```go
package main

import "fmt"

func main() {
  var x int = 42
  var ptr *int = &x

  fmt.Println("Value of x:", x)
  fmt.Println("Address of x:", &x)
  fmt.Println("Pointer ptr:", ptr)
  fmt.Println("Dereferenced value:", *ptr)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Value of x: 42
Address of x: 0x...
Pointer ptr: 0x...
Dereferenced value: 42
```

Demonstrates pointer declaration, address operator (&), and dereferencing (*).

- & gives the address of a variable.
- * dereferences a pointer to get its value.

#### Pointer modification

```go
package main

import "fmt"

func main() {
  x := 10
  ptr := &x

  fmt.Println("Before:", x)
  *ptr = 20
  fmt.Println("After dereference assignment:", x)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Before: 10
After dereference assignment: 20
```

Shows how to modify a value through a pointer.

- *ptr = value modifies the value that ptr points to.

#### Nil pointers

```go
package main

import "fmt"

func main() {
  var ptr *int
  fmt.Println("Nil pointer:", ptr)
  fmt.Println("Is nil:", ptr == nil)

  x := 5
  ptr = &x
  fmt.Println("After assignment:", ptr)
  fmt.Println("Is nil:", ptr == nil)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Nil pointer: <nil>
Is nil: true
After assignment: 0x...
Is nil: false
```

Demonstrates nil pointers and nil checking.

- Uninitialized pointers are nil.
- Always check if a pointer is nil before dereferencing to avoid panic.

**Best practices:**

- Check for nil pointers before dereferencing.
- Use pointers for large structs to avoid copying.
- Document functions that take pointers clearly.

**Common errors:**

- **Panic: nil pointer dereference**: Check if pointer is nil before dereferencing with if ptr != nil.
- **Taking address of non-addressable value**: Only addressable values can use &; literals often cannot.

**Advanced notes:**

- **Pointers to pointers:** Go supports pointers to pointers: var pp **int
- **Function pointers:** Functions can be assigned to pointer variables for callbacks.

## Control Flow

Conditionals, switch statements, and loops in Go.

### Conditionals

If/else statements, multiple conditions, and short statements in conditions.

**Keywords:** if, else, condition, logical operators

#### Simple if/else

```go
package main

import "fmt"

func main() {
  x := 10
  if x > 5 {
    fmt.Println("x is greater than 5")
  } else {
    fmt.Println("x is not greater than 5")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
x is greater than 5
```

Basic if/else statement for conditional execution.

- Braces are required in Go, even for single-statement blocks.

#### Else if chains

```go
package main

import "fmt"

func main() {
  score := 85
  if score >= 90 {
    fmt.Println("Grade: A")
  } else if score >= 80 {
    fmt.Println("Grade: B")
  } else if score >= 70 {
    fmt.Println("Grade: C")
  } else {
    fmt.Println("Grade: F")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
Grade: B
```

Chains multiple conditions with else if.

- else if is used for multiple conditions in sequence.

#### Short statement in condition

```go
package main

import "fmt"

func main() {
  if x := 10; x > 5 {
    fmt.Println("x is greater than 5")
  } else if x < 5 {
    fmt.Println("x is less than 5")
  } else {
    fmt.Println("x equals 5")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
x is greater than 5
```

Declares a variable in the if condition using a short statement.

- Variables declared in if condition are scoped to the if/else block.

**Best practices:**

- Avoid deeply nested if/else statements; use early returns instead.
- Use short statements in conditions for scoped variables.
- Keep conditions simple and readable.

**Common errors:**

- **Missing braces**: Go requires braces even for single-line statements.
- **Variable scope issues**: Remember variables declared in if are scoped to that block.

### Switch Statements

Switch/case statements, fallthrough, and type switches.

**Keywords:** switch, case, default, fallthrough, type switch

#### Basic switch

```go
package main

import "fmt"

func main() {
  day := 3
  switch day {
  case 1:
    fmt.Println("Monday")
  case 2:
    fmt.Println("Tuesday")
  case 3:
    fmt.Println("Wednesday")
  default:
    fmt.Println("Unknown day")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
Wednesday
```

Basic switch statement with multiple cases and default.

- No case value matches another; each case is independent.

#### Switch with fallthrough

```go
package main

import "fmt"

func main() {
  fruit := "apple"
  switch fruit {
  case "apple":
    fmt.Println("Red fruit")
    fallthrough
  case "cherry":
    fmt.Println("Small fruit")
  case "banana":
    fmt.Println("Yellow fruit")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
Red fruit
Small fruit
```

Demonstrates fallthrough to execute multiple cases.

- fallthrough executes the next case's statements.

#### Type switch

```go
package main

import "fmt"

func main() {
  var value interface{} = "hello"

  switch v := value.(type) {
  case string:
    fmt.Println("String value:", v)
  case int:
    fmt.Println("Int value:", v)
  case float64:
    fmt.Println("Float value:", v)
  default:
    fmt.Println("Unknown type")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
String value: hello
```

Uses type assertion with switch to handle different types.

- Type switch uses .(type) to check the underlying type.
- Useful for working with interface{} values.

**Best practices:**

- Use switch instead of long if/else chains.
- Avoid fallthrough unless absolutely necessary.
- Use type switch for working with interface{}.

**Common errors:**

- **Unreachable code after fallthrough**: fallthrough must be the last statement in a case.

### Loops

For loops, range iteration, and while-like loops.

**Keywords:** for, range, break, continue, loop

#### Traditional for loop

```go
package main

import "fmt"

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

_exec_
```go
go run main.go
```

_output_
```go
Iteration: 0
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
```

Demonstrates a traditional for loop with initialization, condition, and increment.

- Go only has for loops, no while; use for without condition for while behavior.

#### Range iteration

```go
package main

import "fmt"

func main() {
  fruits := []string{"apple", "banana", "cherry"}
  for idx, fruit := range fruits {
    fmt.Println(idx, "-", fruit)
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
0 - apple
1 - banana
2 - cherry
```

Uses range to iterate over slices with index and value.

- range provides both index and value; use _ to ignore either.

#### Infinite loop with break

```go
package main

import "fmt"

func main() {
  count := 0
  for {
    fmt.Println("Count:", count)
    count++
    if count >= 3 {
      break
    }
  }
  fmt.Println("Done!")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Count: 0
Count: 1
Count: 2
Done!
```

Infinite loop using for without condition, exited with break.

- for {} creates an infinite loop; break exits early.

**Best practices:**

- Use range for iterating over slices, arrays, and maps.
- Use break and continue to control loop flow.
- Keep loop logic simple and readable.

**Common errors:**

- **Infinite loop**: Make sure the loop condition can become false, or use break.
- **Off-by-one errors with range**: Remember range index goes from 0 to len(slice)-1.

**Advanced notes:**

- **Labeled break:** Use labels with break to exit nested loops: OuterLoop: for ...
- **Continue:** continue skips to the next iteration of the loop.

## Functions and Methods

Function definition, return types, lambdas, closures, and methods.

### Function Definition

Functions with parameters, return types, and multiple returns.

**Keywords:** func, parameters, return, named returns

#### Simple function

```go
package main

import "fmt"

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

func main() {
  result := add(5, 3)
  fmt.Println("Sum:", result)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Sum: 8
```

Defines a simple function with parameters and a return value.

- Parameters must include their type.
- Return type comes after parameter list.

#### Multiple return values

```go
package main

import "fmt"

func divide(a, b float64) (float64, error) {
  if b == 0 {
    return 0, fmt.Errorf("division by zero")
  }
  return a / b, nil
}

func main() {
  result, err := divide(10, 2)
  if err != nil {
    fmt.Println("Error:", err)
  } else {
    fmt.Println("Result:", result)
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
Result: 5
```

Demonstrates multiple return values, commonly used for error handling.

- Multiple returns are wrapped in parentheses.
- Idiomatic Go returns an error as the last return value.

#### Named return values

```go
package main

import "fmt"

func swap(a, b string) (first string, second string) {
  first = b
  second = a
  return
}

func main() {
  x, y := swap("hello", "world")
  fmt.Println(x, y)
}
```

_exec_
```go
go run main.go
```

_output_
```go
world hello
```

Uses named return values that can be returned implicitly.

- Named returns instantiate variables; return without args returns them.

**Best practices:**

- Keep functions focused and single-purpose.
- Return errors as the last return value.
- Document functions with comments above the declaration.

**Common errors:**

- **Too many return values**: Make sure the return signature matches what the function actually returns.
- **Unused return values**: Assign to _ to explicitly ignore values: _, err := func().

**Advanced notes:**

- **Variadic functions:** Use ... to accept variable number of arguments: func sum(nums ...int)
- **Function types:** Functions are first-class; assign to variables: var f func(int) string

### Lambdas and Closures

Anonymous functions, function literals, and closures.

**Keywords:** anonymous function, closure, lambda, first-class

#### Anonymous function

```go
package main

import "fmt"

func main() {
  func(name string) {
    fmt.Println("Hello,", name)
  }("Go")

  greet := func(name string) string {
    return "Hi, " + name
  }
  fmt.Println(greet("Gopher"))
}
```

_exec_
```go
go run main.go
```

_output_
```go
Hello, Go
Hi, Gopher
```

Demonstrates anonymous functions called immediately and assigned to variables.

- Anonymous functions can be called immediately or assigned.

#### Closure capturing variables

```go
package main

import "fmt"

func main() {
  x := 10
  increment := func() {
    x++
  }
  increment()
  fmt.Println("x after closure:", x)
}
```

_exec_
```go
go run main.go
```

_output_
```go
x after closure 11
```

Closure captures and modifies the outer variable x.

- Closures capture variables by reference, not by value.

#### Higher-order function

```go
package main

import "fmt"

func apply(f func(int) int, value int) int {
  return f(value)
}

func main() {
  square := func(x int) int {
    return x * x
  }
  result := apply(square, 5)
  fmt.Println("Square of 5:", result)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Square of 5 25
```

Demonstrates higher-order functions that take functions as parameters.

- Functions are first-class values in Go.

**Best practices:**

- Use closures for callbacks and factory functions.
- Be aware of closure variable captures when using concurrency.
- Keep anonymous functions short and focused.

**Common errors:**

- **Loop variable captured incorrectly in closures**: Copy loop variable: for _, v := range slice { v := v; func uses v }

**Advanced notes:**

- **Closure state:** Each function call can have its own closure state.
- **Partial application:** Use closures to implement partial application patterns.

### Methods

Methods with receivers, pointer receivers, and method sets.

**Keywords:** method, receiver, pointer receiver, value receiver

#### Value receiver method

```go
package main

import "fmt"

type Circle struct {
  Radius float64
}

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

func main() {
  circle := Circle{Radius: 5}
  fmt.Println("Area:", circle.Area())
}
```

_exec_
```go
go run main.go
```

_output_
```go
Area: 78.5
```

Defines a method with a value receiver; the receiver is a copy.

- Value receiver receives a copy; modifications don't affect original.

#### Pointer receiver method

```go
package main

import "fmt"

type Counter struct {
  Count int
}

func (c *Counter) Increment() {
  c.Count++
}

func main() {
  counter := &Counter{Count: 0}
  counter.Increment()
  counter.Increment()
  fmt.Println("Count:", counter.Count)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Count: 2
```

Uses pointer receiver to modify the receiver's state.

- Pointer receiver allows modification of the receiver.

#### Multiple methods on same type

```go
package main

import "fmt"

type Rectangle struct {
  Width, Height float64
}

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

func (r Rectangle) Perimeter() float64 {
  return 2 * (r.Width + r.Height)
}

func main() {
  rect := Rectangle{Width: 5, Height: 3}
  fmt.Println("Area:", rect.Area())
  fmt.Println("Perimeter:", rect.Perimeter())
}
```

_exec_
```go
go run main.go
```

_output_
```go
Area: 15
Perimeter: 16
```

Defines multiple methods on the same struct type.

- Go supports methods on any named type, not just structs.

**Best practices:**

- Use pointer receivers when the method modifies the receiver.
- Use value receivers when the method only reads from the receiver.
- Group related methods on the same type.

**Common errors:**

- **Cannot modify receiver with value receiver**: Change to pointer receiver: func (p *Type) Method().

**Advanced notes:**

- **Method sets:** Only pointer receivers are in the method set of a pointer type.
- **Methods on non-struct types:** You can define methods on any named type: type MyInt int

## Packages and Interfaces

Package organization, imports, exporting, and interfaces.

### Packages

Package declaration, imports, and import aliases.

**Keywords:** package, import, alias, namespace

#### Single and grouped imports

```go
package main

import (
  "fmt"
  "math"
  "strings"
)

func main() {
  fmt.Println(strings.ToUpper("hello"))
  fmt.Println("Pi:", math.Pi)
}
```

_exec_
```go
go run main.go
```

_output_
```go
HELLO
Pi: 3.141592653589793
```

Shows grouped import syntax with multiple standard library packages.

- Use parentheses to group multiple imports.
- Imports are automatically sorted alphabetically.

#### Import aliases

```go
package main

import (
  fmt_pkg "fmt"
  m "math"
)

func main() {
  fmt_pkg.Println("Alias demo")
  fmt_pkg.Println("Pi:", m.Pi)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Alias demo
Pi: 3.141592653589793
```

Uses import aliases to rename package names.

- Aliases are useful for avoiding naming conflicts or shortening long names.

#### Package organization

```go
// File: myapp/utils/string.go
package utils

import "strings"

func Reverse(s string) string {
  runes := []rune(s)
  for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
    runes[i], runes[j] = runes[j], runes[i]
  }
  return string(runes)
}
```

Shows a package organization example with custom package structure.

- Package name matches directory name (usually).

**Best practices:**

- Use clear, concise package names (usually single words).
- Keep related functionality in the same package.
- Avoid circular package dependencies.

**Common errors:**

- **Package initialization loop**: Restructure packages to avoid circular dependencies.

### Exporting

Exported vs unexported identifiers, naming conventions.

**Keywords:** export, uppercase, public, private

#### Exported function and variable

```go
package math

var MaxValue = 999999

func Add(a, b int) int {
  return a + b
}

func private() {
  // This function is unexported
}
```

Shows exported (capitalized) and unexported (lowercase) identifiers.

- Exported names start with uppercase letters.
- Unexported names start with lowercase and are only visible within the package.

#### Exported struct and fields

```go
package person

type Person struct {
  Name string
  age  int
}

func NewPerson(name string, age int) *Person {
  return &Person{Name: name, age: age}
}
```

Struct with exported Name field and unexported age field.

- Exported struct fields are capitalized.
- Use constructor functions (NewType) for creating instances.

**Best practices:**

- Use exported names only for the public API.
- Capitalize exported types, variables, and functions.
- Use constructor functions for complex initialization.

**Common errors:**

- **Cannot access unexported field**: Fields and functions must start with uppercase to be exported.

### Interfaces

Interface definition, implicit implementation, type assertions.

**Keywords:** interface, type assertion, empty interface, implicit implementation

#### Basic interface

```go
package main

import "fmt"

type Writer interface {
  Write(string) error
}

type File struct{}

func (f File) Write(content string) error {
  fmt.Println("Writing:", content)
  return nil
}

func SaveData(w Writer, data string) {
  w.Write(data)
}

func main() {
  file := File{}
  SaveData(file, "Hello World")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Writing: Hello World
```

Demonstrates interface definition and implicit implementation.

- Types automatically satisfy interfaces if they implement all methods.

#### Type assertion

```go
package main

import "fmt"

func main() {
  var val interface{} = "hello"

  if str, ok := val.(string); ok {
    fmt.Println("String:", str)
  } else {
    fmt.Println("Not a string")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
String: hello
```

Uses type assertion to extract the underlying type from interface{}.

- Type assertion panics if the type is wrong; use ok to safely check.

#### Empty interface

```go
package main

import "fmt"

func Print(v interface{}) {
  fmt.Println("Value:", v)
}

func main() {
  Print(42)
  Print("hello")
  Print(3.14)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Value: 42
Value: hello
Value: 3.14
```

Uses interface{} to accept values of any type.

- interface{} is the empty interface that every type implements.

**Best practices:**

- Design small, focused interfaces.
- Use interface{} sparingly; prefer explicit types when possible.
- Use type assertions with the ok pattern to safely check types.

**Common errors:**

- **Panic on incorrect type assertion**: Use the two-value form: value, ok := assertion.

**Advanced notes:**

- **Interface composition:** Interfaces can embed other interfaces: type ReadWriter interface { Reader; Writer }
- **Satisfying multiple interfaces:** A type can implicitly satisfy multiple interfaces.

## Concurrency

Goroutines, channels, and synchronization patterns.

### Goroutines

Creating goroutines with go keyword and concurrent execution.

**Keywords:** goroutine, concurrent, go keyword, lightweight

#### Simple goroutine

```go
package main

import (
  "fmt"
  "time"
)

func printNumbers() {
  for i := 1; i <= 3; i++ {
    fmt.Println("Number:", i)
    time.Sleep(100 * time.Millisecond)
  }
}

func main() {
  go printNumbers()
  time.Sleep(500 * time.Millisecond)
  fmt.Println("Main done")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Number: 1
Number: 2
Number: 3
Main done
```

Launches a goroutine with the go keyword for concurrent execution.

- go launches a goroutine; main must wait for goroutines to complete.

#### Multiple goroutines

```go
package main

import (
  "fmt"
  "time"
)

func worker(id int) {
  for i := 0; i < 2; i++ {
    fmt.Printf("Worker %d: task %d\n", id, i)
    time.Sleep(50 * time.Millisecond)
  }
}

func main() {
  for i := 1; i <= 3; i++ {
    go worker(i)
  }
  time.Sleep(200 * time.Millisecond)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Worker 1: task 0
Worker 2: task 0
Worker 3: task 0
Worker 1: task 1
Worker 2: task 1
Worker 3: task 1
```

Launches multiple goroutines for concurrent task execution.

- Goroutines are lightweight; thousands can run concurrently.

#### Goroutine with closure

```go
package main

import (
  "fmt"
  "time"
)

func main() {
  for i := 1; i <= 3; i++ {
    i := i
    go func() {
      fmt.Println("Goroutine:", i)
    }()
  }
  time.Sleep(100 * time.Millisecond)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Goroutine: 1
Goroutine: 2
Goroutine: 3
```

Uses closures in goroutines; copies loop variable to avoid race conditions.

- Copy loop variables in closures: i := i before the goroutine.

**Best practices:**

- Use channels to communicate between goroutines.
- Copy loop variables when launching goroutines in loops.
- Avoid relying on sleep for synchronization; use channels or sync primitives.

**Common errors:**

- **All goroutines are asleep**: Make the main goroutine wait for the others to complete.
- **Race condition with loop variables**: Copy loop variable: i := i inside the loop before goroutine.

**Advanced notes:**

- **CPU cores usage:** Use runtime.NumCPU() to get available CPU cores for goroutine scheduling.
- **GOMAXPROCS:** Control maximum number of goroutines running simultaneously.

### Channels

Channel creation, sending/receiving, and channel directions.

**Keywords:** channel, make, send, receive, buffer

#### Basic channel

```go
package main

import "fmt"

func main() {
  messages := make(chan string)

  go func() {
    messages <- "Hello"
  }()

  msg := <-messages
  fmt.Println(msg)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Hello
```

Creates a channel and passes data between goroutines.

- <- is the send/receive operator; direction depends on context.

#### Receive pattern

```go
package main

import "fmt"

func main() {
  results := make(chan string, 2)

  go func() {
    results <- "Task 1"
    results <- "Task 2"
  }()

  fmt.Println(<-results)
  fmt.Println(<-results)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Task 1
Task 2
```

Uses a buffered channel to receive multiple values.

- make(chan Type, capacity) creates a buffered channel.

#### Ranging over channels

```go
package main

import "fmt"

func main() {
  numbers := make(chan int)

  go func() {
    for i := 1; i <= 3; i++ {
      numbers <- i
    }
    close(numbers)
  }()

  for num := range numbers {
    fmt.Println(num)
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
1
2
3
```

Uses range to iterate over channel values until close.

- close closes the channel; range exits when channel is closed.

**Best practices:**

- Close channels from the sender side.
- Use buffered channels to prevent deadlocks.
- Prefer range loops over explicit receives for iterating channels.

**Common errors:**

- **Deadlock: all goroutines asleep**: Make sure the sender and receiver are synchronized.
- **Sending on closed channel**: Only senders should close channels; receivers cannot close.

**Advanced notes:**

- **Channel direction:** Restrict channel direction: chan<- Type (send-only), <-chan Type (receive-only)
- **Select statement:** Handle multiple channel operations with select.

### Buffered Channels and Sync

Buffered channels, channel closing, and WaitGroup synchronization.

**Keywords:** buffered channel, close, WaitGroup, sync, synchronization

#### Buffered channels

```go
package main

import "fmt"

func main() {
  messages := make(chan string, 2)

  messages <- "First"
  messages <- "Second"
  messages <- "Third"

  fmt.Println(<-messages)
  fmt.Println(<-messages)
  fmt.Println(<-messages)
}
```

_exec_
```go
go run main.go
```

_output_
```go
First
Second
Third
```

Buffered channel with capacity allows sending without immediate receiver.

- Buffered channels have a fixed capacity.
- Sending blocks only when buffer is full.

#### Ranging over channel

```go
package main

import "fmt"

func main() {
  ch := make(chan int, 3)
  ch <- 1
  ch <- 2
  ch <- 3
  close(ch)

  for value := range ch {
    fmt.Println(value)
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
1
2
3
```

Iterates over channel until it is closed.

- close signals that no more values will be sent.
- range exits when the channel is closed.

#### WaitGroup for synchronization

```go
package main

import (
  "fmt"
  "sync"
)

func main() {
  var wg sync.WaitGroup

  for i := 1; i <= 3; i++ {
    wg.Add(1)
    go func(id int) {
      defer wg.Done()
      fmt.Println("Worker", id)
    }(i)
  }

  wg.Wait()
  fmt.Println("All workers done")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Worker 1
Worker 2
Worker 3
All workers done
```

Uses sync.WaitGroup to wait for all goroutines to complete.

- Add increments counter, Done decrements, Wait blocks until zero.

**Best practices:**

- Use WaitGroup for simple synchronization patterns.
- Use channels for communicating values between goroutines.
- Close channels only when all sends are complete.

**Common errors:**

- **panic: send on closed channel**: Only close channels from the sender, after all sends complete.
- **WaitGroup counter went negative**: Only call Done as many times as Add was called.

**Advanced notes:**

- **Mutex:** Use sync.Mutex for protecting shared data: lock/unlock operations.
- **Select with channels:** Use select to handle multiple channel operations: select { case <-ch1: }

## Advanced Features

Error handling, defer/panic/recover, type conversion, and maps.

### Error Handling

Error interface, returning errors, and error checking patterns.

**Keywords:** error, error interface, error handling, error checking

#### Returning errors

```go
package main

import (
  "fmt"
  "errors"
)

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

func main() {
  result, err := divide(10, 2)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println("Result:", result)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Result: 5
```

Returns error as second value; check before using the result.

- Error is returned as the last value in Go.
- Check error immediately after the function call.

#### Custom errors

```go
package main

import (
  "fmt"
  "errors"
)

type ValidationError struct {
  Field string
  Message string
}

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

func main() {
  err := ValidationError{"Email", "Invalid format"}
  fmt.Println(err)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Email: Invalid format
```

Implements custom error type with Error method.

- Implement Error() string method to satisfy error interface.

#### Error wrapping

```go
package main

import (
  "fmt"
  "errors"
)

func main() {
  err := errors.New("database error")
  wrapped := fmt.Errorf("failed to save user: %w", err)
  fmt.Println(wrapped)

  if errors.Is(wrapped, err) {
    fmt.Println("Found the original error")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
failed to save user: database error
Found the original error
```

Wraps errors with context while preserving the original error.

- Use %w in fmt.Errorf to wrap errors.
- Use errors.Is to check for specific errors.

**Best practices:**

- Always check for errors immediately after function calls.
- Return errors as the last value in functions.
- Use fmt.Errorf with %w to wrap errors with context.
- Implement Error() for custom error types.

**Common errors:**

- **Ignoring errors with underscore**: Never ignore errors; check and handle them explicitly.
- **Using string errors instead of error type**: Return error type, not string; use errors.New or custom types.

**Advanced notes:**

- **Error As:** Use errors.As to extract specific error types: errors.As(err, &target)
- **Unwrap:** Get original error from wrapped error with Unwrap method.

### Defer, Panic, and Recover

Defer execution, panic for unrecoverable errors, and recover from panic.

**Keywords:** defer, panic, recover, cleanup

#### Defer for cleanup

```go
package main

import "fmt"

func main() {
  file := "data.txt"
  fmt.Println("Opening", file)
  defer fmt.Println("Closing", file)

  fmt.Println("Processing file")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Opening data.txt
Processing file
Closing data.txt
```

defer runs the given code when the function exits.

- defer executes when the function returns or panics.

#### Panic usage

```go
package main

import "fmt"

func safeDivide(a, b int) int {
  if b == 0 {
    panic("division by zero")
  }
  return a / b
}

func main() {
  defer func() {
    if r := recover(); r != nil {
      fmt.Println("Recovered from:", r)
    }
  }()

  result := safeDivide(10, 0)
  fmt.Println(result)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Recovered from: division by zero
```

Uses panic for errors and recover to handle them.

- panic stops execution; recover returns the panic value in defer.

#### Multiple defers

```go
package main

import "fmt"

func main() {
  fmt.Println("Start")

  defer fmt.Println("First defer")
  defer fmt.Println("Second defer")
  defer fmt.Println("Third defer")

  fmt.Println("End")
}
```

_exec_
```go
go run main.go
```

_output_
```go
Start
End
Third defer
Second defer
First defer
```

Defers execute in LIFO (Last In, First Out) order.

- Multiple defers form a stack; last defer executes first.

**Best practices:**

- Use defer for cleanup operations like closing files.
- Avoid panic; return errors instead for normal error conditions.
- Use recover only inside a defer to handle panics.

**Common errors:**

- **Defer order confusion**: Remember defers execute in LIFO order (reverse declaration order).
- **recover returns nil outside defer**: Only call recover inside a defer; it returns nil elsewhere.

**Advanced notes:**

- **Defer argument evaluation:** Arguments to deferred functions are evaluated immediately, not at call time.
- **Defer with methods:** Defer can call methods: defer obj.Close()

### Type Conversion and Maps

Type conversion syntax, maps/dictionaries, and type switching.

**Keywords:** type conversion, map, dictionary, type assertion

#### Type conversion

```go
package main

import "fmt"

func main() {
  var x int32 = 42
  y := int64(x)
  z := float64(x)

  fmt.Println("Original:", x)
  fmt.Println("To int64:", y)
  fmt.Println("To float64:", z)
}
```

_exec_
```go
go run main.go
```

_output_
```go
Original: 42
To int64: 42
To float64: 42
```

Converts between compatible types using Type(value) syntax.

- Type conversion is explicit; implicit conversions are not allowed.

#### Map creation and access

```go
package main

import "fmt"

func main() {
  scores := map[string]int{
    "Alice": 90,
    "Bob": 85,
    "Charlie": 92,
  }

  fmt.Println("Alice's score:", scores["Alice"])
  scores["David"] = 88
  fmt.Println("David's score:", scores["David"])

  if val, ok := scores["Eve"]; ok {
    fmt.Println("Eve's score:", val)
  } else {
    fmt.Println("Eve not found")
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
Alice's score: 90
David's score: 88
Eve not found
```

Creates and manipulates maps with key-value pairs.

- Maps are unordered; use two-value receive to check existence.

#### Iterating over maps

```go
package main

import "fmt"

func main() {
  colors := map[string]string{
    "red":   "#FF0000",
    "green": "#00FF00",
    "blue":  "#0000FF",
  }

  for name, hex := range colors {
    fmt.Printf("%s: %s\n", name, hex)
  }
}
```

_exec_
```go
go run main.go
```

_output_
```go
red: #FF0000
green: #00FF00
blue: #0000FF
```

Iterates over map keys and values using range.

- Maps are iterated in random order; use ordering if needed.

**Best practices:**

- Use the ok pattern to check map key existence.
- Remember maps are unordered; don't rely on iteration order.
- Use explicit type conversion only for compatible types.

**Common errors:**

- **Accessing missing map key returns zero value silently**: Use the two-value form: if val, ok := m[key].
- **Incompatible type conversion**: Only convert between compatible types; check at compile time.

**Advanced notes:**

- **Map of maps:** Create nested maps: map[string]map[string]int
- **Delete from map:** Use delete(map, key) to remove entries from a map.
