---
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, making it ideal for building fast, scalable server applications and system tools.

Browse the sections below to explore 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

Explore 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.
- Capacity is useful for performance optimization to avoid reallocations.

**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**: Ensure 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**: Ensure function return signature matches actual 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**: Ensure main goroutine waits for other goroutines 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**: Ensure sender and receiver are synchronized properly.
- **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 gracefully when 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; ensure sends complete first.
- **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 ensures code runs 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 in defer to handle panics gracefully.

**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.
