Skip to content

Go (Golang) Cheatsheet

Basics

Hello World

package main

import "fmt"

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

Running Go Programs

go run main.go          # Run directly
go build main.go        # Compile to binary
go install              # Install package

Variables and Constants

Variable Declaration

// Explicit type
var name string = "John"

// Type inference
var age = 30

// Short declaration (inside functions only)
city := "New York"

// Multiple variables
var (
    firstName string = "Jane"
    lastName  string = "Doe"
    userAge   int    = 25
)

// Multiple assignment
x, y := 10, 20

Constants

const Pi = 3.14159
const (
    StatusOK       = 200
    StatusNotFound = 404
)

// iota - constant generator
const (
    Sunday = iota  // 0
    Monday         // 1
    Tuesday        // 2
)

Data Types

Basic Types

// Integers
int, int8, int16, int32, int64
uint, uint8, uint16, uint32, uint64

// Floating point
float32, float64

// Complex numbers
complex64, complex128

// Boolean
bool  // true or false

// String
string

// Byte (alias for uint8)
byte

// Rune (alias for int32, represents Unicode code point)
rune

Type Conversion

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

str := string(65)  // "A"

Zero Values

var i int       // 0
var f float64   // 0.0
var b bool      // false
var s string    // ""
var p *int      // nil

Operators

Arithmetic

+  // Addition
-  // Subtraction
*  // Multiplication
/  // Division
%  // Modulus
++ // Increment
-- // Decrement

Comparison

==  // Equal to
!=  // Not equal to
<   // Less than
>   // Greater than
<=  // Less than or equal to
>=  // Greater than or equal to

Logical

&&  // Logical AND
||  // Logical OR
!   // Logical NOT

Bitwise

&   // AND
|   // OR
^   // XOR
<<  // Left shift
>>  // Right shift

Control Structures

If-Else

if x > 0 {
    fmt.Println("Positive")
} else if x < 0 {
    fmt.Println("Negative")
} else {
    fmt.Println("Zero")
}

// If with short statement
if err := doSomething(); err != nil {
    fmt.Println("Error:", err)
}

Switch

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

// Switch without condition (like if-else chain)
switch {
case x < 0:
    fmt.Println("Negative")
case x > 0:
    fmt.Println("Positive")
default:
    fmt.Println("Zero")
}

// Type switch
switch v := i.(type) {
case int:
    fmt.Println("Integer:", v)
case string:
    fmt.Println("String:", v)
default:
    fmt.Println("Unknown type")
}

Loops

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

// While-style loop
for x < 100 {
    x++
}

// Infinite loop
for {
    // Loop forever
    break  // Exit loop
}

// Range loop
numbers := []int{1, 2, 3, 4, 5}
for index, value := range numbers {
    fmt.Println(index, value)
}

// Ignore index
for _, value := range numbers {
    fmt.Println(value)
}

// Only index
for index := range numbers {
    fmt.Println(index)
}

Defer, Panic, Recover

// Defer - executes after function returns
defer fmt.Println("World")
fmt.Println("Hello")  // Prints: Hello, then World

// Panic - stops normal execution
panic("Something went wrong!")

// Recover - regain control after panic
func safeFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()
    panic("Oops!")
}

Functions

Basic Function

func add(x int, y int) int {
    return x + y
}

// Short form when parameters share type
func multiply(x, y int) int {
    return x * y
}

Multiple Return Values

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

result, err := divide(10, 2)

Named Return Values

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

Variadic Functions

func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

sum(1, 2, 3, 4, 5)

Anonymous Functions & Closures

// Anonymous function
func() {
    fmt.Println("Anonymous")
}()

// Closure
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

c := counter()
fmt.Println(c())  // 1
fmt.Println(c())  // 2

Arrays and Slices

Arrays (Fixed Size)

var arr [5]int
arr[0] = 1

// Array literal
primes := [5]int{2, 3, 5, 7, 11}

// Auto count
arr := [...]int{1, 2, 3, 4, 5}

Slices (Dynamic Size)

// Create slice
var s []int
s = []int{1, 2, 3, 4, 5}

// Make slice with length and capacity
s := make([]int, 5)      // len=5, cap=5
s := make([]int, 0, 5)   // len=0, cap=5

// Slice from array
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4]  // [2, 3, 4]

// Append to slice
s = append(s, 6)
s = append(s, 7, 8, 9)

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

// Length and capacity
len(s)
cap(s)

Maps

Creating Maps

// Make map
var m map[string]int
m = make(map[string]int)

// Map literal
ages := map[string]int{
    "Alice": 25,
    "Bob":   30,
}

// Short form
m := make(map[string]int)

Map Operations

// Set value
m["key"] = 42

// Get value
value := m["key"]

// Check if key exists
value, ok := m["key"]
if ok {
    fmt.Println("Key exists:", value)
}

// Delete key
delete(m, "key")

// Iterate over map
for key, value := range m {
    fmt.Println(key, value)
}

// Length
len(m)

Structs

Defining and Using Structs

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

// Create instance
p1 := Person{Name: "Alice", Age: 30, City: "NYC"}
p2 := Person{"Bob", 25, "LA"}  // In order

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

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

// Anonymous struct
dog := struct {
    Name  string
    Breed string
}{
    Name:  "Max",
    Breed: "Labrador",
}

Embedded Structs

type Address struct {
    Street string
    City   string
}

type Employee struct {
    Name    string
    Address  // Embedded struct
}

e := Employee{
    Name: "John",
    Address: Address{
        Street: "123 Main St",
        City:   "Boston",
    },
}
fmt.Println(e.City)  // Direct access

Pointers

Pointer Basics

// Declare pointer
var p *int

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

// Dereference pointer
fmt.Println(*p)  // 42
*p = 21
fmt.Println(x)   // 21

// New function
p := new(int)
*p = 100

Interfaces

Defining Interfaces

type Shape interface {
    Area() float64
    Perimeter() float64
}

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)
}

// Using interface
var s Shape = Rectangle{Width: 10, Height: 5}
fmt.Println(s.Area())

Empty Interface

// Can hold any type
var i interface{}
i = 42
i = "hello"
i = true

// Type assertion
value, ok := i.(string)
if ok {
    fmt.Println("String:", value)
}

Common Interfaces

// Stringer
type Stringer interface {
    String() string
}

// Error
type error interface {
    Error() string
}

Methods

Methods on Structs

type Person struct {
    Name string
    Age  int
}

// Value receiver
func (p Person) Greet() string {
    return "Hello, " + p.Name
}

// Pointer receiver
func (p *Person) HaveBirthday() {
    p.Age++
}

p := Person{Name: "Alice", Age: 30}
p.Greet()
p.HaveBirthday()

Error Handling

Creating Errors

import "errors"

// Simple error
err := errors.New("something went wrong")

// Formatted error
err := fmt.Errorf("invalid value: %d", value)

Custom Error Types

type MyError struct {
    Code    int
    Message string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}

Error Handling Pattern

result, err := doSomething()
if err != nil {
    return err  // or handle it
}
// Use result

Concurrency

Goroutines

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

go myFunction()

// Wait for goroutines (basic)
time.Sleep(time.Second)

Channels

// Create channel
ch := make(chan int)

// Buffered channel
ch := make(chan int, 5)

// Send to channel
ch <- 42

// Receive from channel
value := <-ch

// Close channel
close(ch)

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

Channel Patterns

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

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

WaitGroup

import "sync"

var wg sync.WaitGroup

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

wg.Wait()

Mutex

import "sync"

var (
    mu      sync.Mutex
    counter int
)

mu.Lock()
counter++
mu.Unlock()

// RWMutex
var rwMu sync.RWMutex
rwMu.RLock()   // Read lock
// Read operations
rwMu.RUnlock()

rwMu.Lock()    // Write lock
// Write operations
rwMu.Unlock()

Packages

Importing Packages

import "fmt"
import "math"

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

// Alias
import f "fmt"

// Import for side effects
import _ "image/png"

Creating Packages

// File: mypackage/mypackage.go
package mypackage

// Exported (capitalized)
func PublicFunction() {
    // Visible outside package
}

// Unexported (lowercase)
func privateFunction() {
    // Only visible within package
}

Init Function

func init() {
    // Runs automatically when package is imported
    // Can have multiple init functions
}

File I/O

Reading Files

import (
    "io/ioutil"
    "os"
)

// Read entire file
data, err := ioutil.ReadFile("file.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(data))

// Read with os.Open
file, err := os.Open("file.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

Writing Files

// Write entire file
data := []byte("Hello, World!")
err := ioutil.WriteFile("file.txt", data, 0644)

// Write with os.Create
file, err := os.Create("file.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

writer := bufio.NewWriter(file)
writer.WriteString("Hello, World!\\n")
writer.Flush()

JSON

Encoding (Marshal)

import "encoding/json"

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

p := Person{Name: "Alice", Age: 30}
jsonData, err := json.Marshal(p)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(jsonData))

// Pretty print
jsonData, err := json.MarshalIndent(p, "", "  ")

Decoding (Unmarshal)

jsonString := `{"name":"Bob","age":25}`
var p Person
err := json.Unmarshal([]byte(jsonString), &p)
if err != nil {
    log.Fatal(err)
}
fmt.Println(p.Name, p.Age)

Testing

Basic Test

// File: mypackage_test.go
package mypackage

import "testing"

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5
    if result != expected {
        t.Errorf("Add(2, 3) = %d; want %d", result, expected)
    }
}

Table-Driven Tests

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, -1, -2},
        {"zero", 0, 5, 5},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("got %d, want %d", result, tt.expected)
            }
        })
    }
}

Benchmarks

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2, 3)
    }
}

Running Tests

go test              # Run tests
go test -v           # Verbose
go test -cover       # Coverage
go test -bench=.     # Run benchmarks

Common Patterns

Constructor Pattern

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

Options Pattern

type Options struct {
    Host string
    Port int
}

type Option func(*Options)

func WithHost(host string) Option {
    return func(o *Options) {
        o.Host = host
    }
}

func NewServer(opts ...Option) *Server {
    options := &Options{
        Host: "localhost",
        Port: 8080,
    }
    for _, opt := range opts {
        opt(options)
    }
    return &Server{options: options}
}

Context Pattern

import "context"

ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()

ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
ctx = context.WithValue(ctx, "key", "value")

Useful Commands

go run main.go           # Run program
go build                 # Build binary
go install               # Install binary
go test                  # Run tests
go fmt                   # Format code
go vet                   # Report suspicious constructs
go mod init module_name  # Initialize module
go mod tidy              # Clean up dependencies
go get package_name      # Install package
go doc package_name      # View documentation