Go logo
Go Cheatsheet
23 of 23 code examples
.go
Hello World
Basic Go program structure
Basics
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}
Variables
Variable declarations
Basics
// Variable declaration
var name string = "John"
var age int = 30

// Type inference
var city = "New York"
var score = 95.5

// Short declaration (inside functions)
country := "USA"
temperature := 25.3

// Multiple variables
var x, y int = 10, 20
a, b := "hello", "world"

// Constants
const Pi = 3.14159
const MaxUsers = 1000
Data Types
Basic data types
Basics
// Basic types
var isActive bool = true
var count int = 42
var price float64 = 19.99
var message string = "Hello"

// Integer types
var a int = 42        // platform-dependent
var b int32 = 100
var c int64 = 1000
var d uint = 50       // unsigned

// Complex numbers
var comp complex128 = complex(2, 3)

// Byte and rune
var ch byte = 'A'     // alias for uint8
var r rune = '世'     // alias for int32
Functions
Function declarations
Functions
// Basic function
func greet(name string) string {
    return "Hello, " + name
}

// Multiple parameters and return values
func calculate(a, b int) (int, int) {
    sum := a + b
    product := a * b
    return sum, product
}

// Named return values
func divide(a, b float64) (result float64, err error) {
    if b == 0 {
        return 0, fmt.Errorf("cannot divide by zero")
    }
    result = a / b
    return
}

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

// Function as parameter
func apply(fn func(int) int, x int) int {
    return fn(x)
}
Control Structures
If, for, switch statements
Basics
// If statement
if age >= 18 {
    fmt.Println("Adult")
} else {
    fmt.Println("Minor")
}

// If with initialization
if score := getScore(); score > 90 {
    fmt.Println("Excellent!")
}

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

// While-like loop
count := 0
for count < 5 {
    fmt.Println(count)
    count++
}

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

// Switch statement
switch day {
case "Monday":
    fmt.Println("Start of week")
case "Friday":
    fmt.Println("Weekend soon!")
default:
    fmt.Println("Regular day")
}
Arrays & Slices
Arrays and dynamic slices
Data Structures
// Arrays (fixed size)
var numbers [5]int = [5]int{1, 2, 3, 4, 5}
names := [3]string{"Alice", "Bob", "Charlie"}

// Slices (dynamic arrays)
var scores []int = []int{85, 90, 78}
grades := make([]int, 0, 10) // length 0, capacity 10

// Slice operations
scores = append(scores, 95)      // Append
sub := scores[1:3]               // Slice
copy(sub, scores)                // Copy

// Iterating slices
for index, value := range scores {
    fmt.Printf("Index %d: %d\n", index, value)
}

// Common slice functions
len(scores)     // Length
cap(scores)     // Capacity
scores[0]       // Access element
Maps
Key-value collections
Data Structures
// Map declaration
ages := make(map[string]int)
ages["Alice"] = 30
ages["Bob"] = 25

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

// Access and check
score, exists := scores["Charlie"]
if exists {
    fmt.Println("Score:", score)
}

// Delete
delete(scores, "Bob")

// Iteration
for name, score := range scores {
    fmt.Printf("%s: %d\n", name, score)
}

// Map functions
len(scores)     // Number of elements
Structs
Custom types and methods
Data Structures
// Struct definition
type Person struct {
    Name    string
    Age     int
    Email   string
}

// Creating instances
p1 := Person{"Alice", 30, "alice@example.com"}
p2 := Person{
    Name:  "Bob",
    Age:   25,
    Email: "bob@example.com",
}

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

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

// Embedded structs
type Employee struct {
    Person
    Department string
    Salary     float64
}

// Using embedded struct
emp := Employee{
    Person:     Person{"Charlie", 35, "charlie@company.com"},
    Department: "Engineering",
    Salary:     75000,
}
Interfaces
Interface types and polymorphism
OOP
// Interface definition
type Shape interface {
    Area() float64
    Perimeter() float64
}

// Struct implementing interface
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)
}

// Another implementation
type Circle struct {
    Radius float64
}

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

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

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

// Empty interface (any type)
func printValue(v interface{}) {
    fmt.Printf("Value: %v, Type: %T\n", v, v)
}
Error Handling
Go error handling patterns
Error Handling
// Basic error handling
result, err := divide(10, 0)
if err != nil {
    fmt.Println("Error:", err)
    return
}
fmt.Println("Result:", result)

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

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

// Error checking helper
func processFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return fmt.Errorf("failed to open file: %w", err)
    }
    defer file.Close()
    
    // Process file...
    return nil
}

// Multiple error handling
if err := processFile("data.txt"); err != nil {
    var valErr ValidationError
    if errors.As(err, &valErr) {
        fmt.Println("Validation error:", valErr)
    } else {
        fmt.Println("Other error:", err)
    }
}
Concurrency - Goroutines
Lightweight threads
Concurrency
// Basic goroutine
go func() {
    fmt.Println("Running in goroutine")
}()

// Goroutine with parameters
for i := 0; i < 5; i++ {
    go func(n int) {
        fmt.Printf("Goroutine %d\n", n)
    }(i)
}

// Wait for goroutines to complete
var wg sync.WaitGroup

for i := 0; i < 3; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        time.Sleep(time.Second)
        fmt.Printf("Task %d completed\n", id)
    }(i)
}

wg.Wait()
fmt.Println("All goroutines completed")
Concurrency - Channels
Communication between goroutines
Concurrency
// Creating channels
messages := make(chan string)
buffered := make(chan int, 10) // buffered channel

// Sending and receiving
go func() {
    messages <- "hello"
}()

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

// Channel with select
select {
case msg := <-messages:
    fmt.Println("Received:", msg)
case <-time.After(time.Second):
    fmt.Println("Timeout")
}

// Range over channel
go func() {
    for i := 0; i < 5; i++ {
        buffered <- i
    }
    close(buffered)
}()

for num := range buffered {
    fmt.Println("Received:", num)
}

// Channel directions
func producer(ch chan<- int) { // send-only
    ch <- 42
}

func consumer(ch <-chan int) { // receive-only
    value := <-ch
    fmt.Println(value)
}
Concurrency - Mutex
Synchronization with mutex
Concurrency
// Safe counter with mutex
type SafeCounter struct {
    mu    sync.Mutex
    value int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *SafeCounter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}

// Using the safe counter
var counter SafeCounter
var wg sync.WaitGroup

for i := 0; i < 1000; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        counter.Increment()
    }()
}

wg.Wait()
fmt.Println("Final count:", counter.Value())

// RWMutex for read-heavy workloads
type Config struct {
    mu   sync.RWMutex
    data map[string]string
}

func (c *Config) Get(key string) string {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.data[key]
}

func (c *Config) Set(key, value string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.data[key] = value
}
File Operations
Reading and writing files
I/O
// Reading entire file
content, err := os.ReadFile("data.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(content))

// Writing file
data := []byte("Hello, World!")
err := os.WriteFile("output.txt", data, 0644)
if err != nil {
    log.Fatal(err)
}

// Reading line by line
file, err := os.Open("data.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

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

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

writer := bufio.NewWriter(file)
fmt.Fprintln(writer, "Hello, World!")
writer.Flush()
JSON Operations
JSON encoding and decoding
Data Formats
// JSON encoding
type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

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

// JSON decoding
var decodedPerson Person
err = json.Unmarshal(jsonData, &decodedPerson)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%+v\n", decodedPerson)

// Streaming JSON encoder
encoder := json.NewEncoder(os.Stdout)
encoder.Encode(person)

// Custom JSON marshaling
func (p Person) MarshalJSON() ([]byte, error) {
    type Alias Person
    return json.Marshal(&struct {
        *Alias
        Formatted string `json:"formatted"`
    }{
        Alias:     (*Alias)(&p),
        Formatted: fmt.Sprintf("%s (%d years)", p.Name, p.Age),
    })
}
HTTP Server
Building web servers
Web
// Basic HTTP server
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
})

http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        users := []string{"Alice", "Bob"}
        json.NewEncoder(w).Encode(users)
    case "POST":
        var user struct{ Name string }
        json.NewDecoder(r.Body).Decode(&user)
        fmt.Fprintf(w, "Created user: %s", user.Name)
    default:
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    }
})

log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))

// With middleware
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("%s %s", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

// Using middleware
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
wrappedMux := loggingMiddleware(mux)
HTTP Client
Making HTTP requests
Web
// GET request
resp, err := http.Get("https://api.example.com/users")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(body))

// POST request with JSON
user := map[string]string{"name": "Alice"}
jsonData, _ := json.Marshal(user)

resp, err := http.Post(
    "https://api.example.com/users",
    "application/json",
    bytes.NewBuffer(jsonData),
)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

// Custom client with timeout
client := &http.Client{
    Timeout: 10 * time.Second,
}

req, err := http.NewRequest("GET", "https://api.example.com/data", nil)
if err != nil {
    log.Fatal(err)
}

req.Header.Add("Authorization", "Bearer token")
resp, err := client.Do(req)
Testing
Writing tests in Go
Testing
// Basic test
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 TestMultiply(t *testing.T) {
    tests := []struct {
        a, b     int
        expected int
    }{
        {2, 3, 6},
        {0, 5, 0},
        {-2, 3, -6},
    }

    for _, test := range tests {
        result := Multiply(test.a, test.b)
        if result != test.expected {
            t.Errorf("Multiply(%d, %d) = %d; want %d", 
                test.a, test.b, result, test.expected)
        }
    }
}

// Benchmark test
func BenchmarkFibonacci(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Fibonacci(20)
    }
}

// Example test (appears in documentation)
func ExampleAdd() {
    sum := Add(1, 2)
    fmt.Println(sum)
    // Output: 3
}
Context
Context for cancellation and timeouts
Concurrency
// Context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// Use context in HTTP request
req, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil)
if err != nil {
    log.Fatal(err)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

// Context with cancellation
ctx, cancel := context.WithCancel(context.Background())

go func() {
    time.Sleep(2 * time.Second)
    cancel() // Cancel the context after 2 seconds
}()

// Check context in long-running operation
select {
case <-time.After(10 * time.Second):
    fmt.Println("Operation completed")
case <-ctx.Done():
    fmt.Println("Operation cancelled:", ctx.Err())
}

// Context with values
type key string
const userKey key = "user"

ctx := context.WithValue(context.Background(), userKey, "alice")
if user, ok := ctx.Value(userKey).(string); ok {
    fmt.Println("User:", user)
}
Defer, Panic, Recover
Error recovery mechanisms
Error Handling
// Defer for cleanup
func processFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close() // Always close the file
    
    // Process file...
    return nil
}

// Multiple defers (LIFO order)
func example() {
    defer fmt.Println("First defer")
    defer fmt.Println("Second defer")
    fmt.Println("Function body")
    // Output: Function body, Second defer, First defer
}

// Panic and recover
func safeDivide(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic occurred: %v", r)
        }
    }()
    
    if b == 0 {
        panic("division by zero")
    }
    
    return a / b, nil
}

// Using recover
result, err := safeDivide(10, 0)
if err != nil {
    fmt.Println("Error:", err)
}
Package Management
Go modules and imports
Packages
// go.mod file example
module github.com/username/myproject

go 1.21

require (
    github.com/gorilla/mux v1.8.0
    github.com/lib/pq v1.10.9
)

// Importing packages
import (
    "fmt"
    "net/http"
    "encoding/json"
    
    "github.com/gorilla/mux"
    "github.com/lib/pq"
)

// Custom package structure
// myproject/
//   go.mod
//   main.go
//   pkg/
//     utils/
//       math.go
//   internal/
//     config/
//       config.go

// In math.go
package utils

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

// Using custom package
import "github.com/username/myproject/pkg/utils"

func main() {
    result := utils.Add(2, 3)
    fmt.Println(result)
}
Real-World: REST API
Complete REST API example
Real World
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "strconv"
    
    "github.com/gorilla/mux"
)

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

var users = []User{
    {ID: 1, Name: "Alice", Email: "alice@example.com"},
    {ID: 2, Name: "Bob", Email: "bob@example.com"},
}

func getUsers(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

func getUser(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id, _ := strconv.Atoi(params["id"])
    
    for _, user := range users {
        if user.ID == id {
            json.NewEncoder(w).Encode(user)
            return
        }
    }
    
    http.Error(w, "User not found", http.StatusNotFound)
}

func createUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    user.ID = len(users) + 1
    users = append(users, user)
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

func main() {
    r := mux.NewRouter()
    
    r.HandleFunc("/users", getUsers).Methods("GET")
    r.HandleFunc("/users/{id}", getUser).Methods("GET")
    r.HandleFunc("/users", createUser).Methods("POST")
    
    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}
Real-World: Worker Pool
Concurrent worker pattern
Real World
package main

import (
    "fmt"
    "sync"
    "time"
)

type Job struct {
    ID   int
    Data string
}

type Result struct {
    JobID int
    Output string
    Err   error
}

func worker(id int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
    defer wg.Done()
    
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job.ID)
        
        // Simulate work
        time.Sleep(time.Second)
        
        result := Result{
            JobID:  job.ID,
            Output: fmt.Sprintf("Processed: %s", job.Data),
        }
        
        results <- result
    }
}

func main() {
    const numWorkers = 3
    const numJobs = 10
    
    jobs := make(chan Job, numJobs)
    results := make(chan Result, numJobs)
    
    var wg sync.WaitGroup
    
    // Start workers
    for i := 1; i <= numWorkers; i++ {
        wg.Add(1)
        go worker(i, jobs, results, &wg)
    }
    
    // Send jobs
    for i := 1; i <= numJobs; i++ {
        jobs <- Job{
            ID:   i,
            Data: fmt.Sprintf("data-%d", i),
        }
    }
    close(jobs)
    
    // Wait for workers to complete
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // Collect results
    for result := range results {
        if result.Err != nil {
            fmt.Printf("Job %d failed: %v\n", result.JobID, result.Err)
        } else {
            fmt.Printf("Job %d result: %s\n", result.JobID, result.Output)
        }
    }
    
    fmt.Println("All jobs completed")
}