Introduction to the GoLang Cheat Sheet
If you’re searching for a clear and practical GoLang cheat sheet, you’re in the right place. Go, or Golang, is a modern programming language developed by Google, known for its speed, simplicity, and excellent support for concurrency. It’s widely used in cloud development, backend systems, DevOps tools, and scalable web applications. This GoLang cheat sheet by Solviyo is your quick reference guide — covering everything from Go syntax and variables to advanced concepts like goroutines, channels, and interfaces. You can read it online or download the GoLang cheat sheet PDF for offline learning.
If you’re completely new to the language, we recommend starting with our beginner’s guide — Go (Golang) for Beginners: Why You Should Learn Go in 2025 . It explains why Go has become one of the most in-demand programming languages for developers, and how it’s shaping the future of backend and cloud development.
Whether you’re a beginner exploring Go for the first time or an experienced developer brushing up on the language before an interview, this guide is designed to help you learn faster. It includes easy-to-follow examples, short explanations, and practical tips — all organized into simple, digestible sections. You’ll find code snippets you can copy, real-world examples, and insights that help you write clean and efficient Go code.
This Go quick reference covers the most essential topics like data types, loops, functions, structs, slices, maps, and error handling. You’ll also find advanced sections on concurrency with goroutines and channels, Go modules, memory management, and idiomatic Go practices. Each topic is explained in plain English, so you can focus more on coding and less on searching for syntax.
For developers preparing for interviews or working on Go projects, this page doubles as a Go programming quick reference. It’s designed to help you recall syntax, commands, and best practices at a glance. And if you prefer learning offline, you can easily download the GoLang cheat sheet PDF version and keep it handy for everyday use. Bookmark this guide — it’s your complete companion for mastering Go in 2025 and beyond.
Hello Go
Installing Go
Install Go for your OS:
# Linux (Ubuntu/Debian)
sudo apt install golang-go
# macOS (Homebrew)
brew install go
# Windows (winget)
winget install Go.Go
# Verify installation
go version
Setting Up Environment
Check your Go environment and key paths:
go env
# Key variables:
# GOROOT: Go installation directory
# GOPATH: Workspace for Go projects
# GOMODCACHE: Module cache directory
Creating a Module
Initialize a module to manage dependencies:
mkdir myproject
cd myproject
go mod init github.com/username/myproject
go mod tidy
First Go Program
Create hello.go:
package main
import "fmt"
func main() {
fmt.Println("Hello from Solviyo!")
}
Run or build:
# Run directly
go run hello.go
# Build binary
go build hello.go
Recommended Editors & Tools
- VS Code: Go extension for syntax highlighting, debugging, and modules.
- GoLand: Full-featured Go IDE by JetBrains.
- Other editors: Sublime Text, Vim/Neovim, Emacs (with Go plugins).
Go Syntax & Basics
Variables
Declare variables using var or short declaration :=:
// Using var
var name string = "Solviyo"
var age int = 25
// Short declaration (only inside functions)
city := "Dhaka"
count := 10
Constants
Use const for values that do not change:
const Pi = 3.14159
const AppName string = "Solviyo Go Cheat Sheet"
Primitive Types & Zero Values
Common Go types and their zero values:
var i int // 0
var f float64 // 0.0
var b bool // false
var s string // ""
Type Aliases & Conversion
Define custom types or convert between types:
// Type alias
type Age int
var myAge Age = 30
// Type conversion
var x int = 10
var y float64 = float64(x)
Type Table
| Type | Zero Value | Typical Use |
|---|---|---|
| int / uint | 0 | Counting, indexes |
| float32 / float64 | 0.0 | Measurements, calculations |
| bool | false | Flags, condition checks |
| string | "" (empty) | Text, messages |
Go Operators & Expressions
Arithmetic Operators
Perform numeric calculations:
a, b := 10, 3
fmt.Println(a + b) // 13
fmt.Println(a - b) // 7
fmt.Println(a * b) // 30
fmt.Println(a / b) // 3
fmt.Println(a % b) // 1
Comparison Operators
Compare values:
x, y := 5, 8
fmt.Println(x == y) // false
fmt.Println(x != y) // true
fmt.Println(x > y) // false
fmt.Println(x < y) // true
fmt.Println(x >= y) // false
fmt.Println(x <= y) // true
Logical Operators
Combine boolean expressions:
p, q := true, false
fmt.Println(p && q) // false
fmt.Println(p || q) // true
fmt.Println(!p) // false
Bitwise Operators
Operate on binary representations:
var m uint = 6 // 110 in binary
var n uint = 3 // 011 in binary
fmt.Println(m & n) // 2 (010)
fmt.Println(m | n) // 7 (111)
fmt.Println(m ^ n) // 5 (101)
fmt.Println(m &^ n) // 4 (100)
fmt.Println(m << 1) // 12 (1100)
fmt.Println(m >> 1) // 3 (011)
Assignment Operators
Shorthand for arithmetic + assignment:
x := 10
x += 5 // x = 15
x -= 3 // x = 12
x *= 2 // x = 24
x /= 4 // x = 6
x %= 4 // x = 2
x &= 3 // x = 2 & 3 = 2
x |= 1 // x = 2 | 1 = 3
x ^= 2 // x = 3 ^ 2 = 1
x <<= 1 // x = 1 << 1 = 2
x >>= 1 // x = 2 >> 1 = 1
Operator Precedence (Summary)
| Precedence | Operators | Example |
|---|---|---|
| Highest | () [] . | function calls, indexing |
| * / % << >> & &^ | multiplication, division, bitwise | |
| + - | ^ | addition, subtraction, bitwise OR/XOR | |
| == != < <= > >= | comparisons | |
| Lowest | && || | logical AND/OR |
() to ensure the correct evaluation order when combining multiple operators.Go Control Flow
If Statements
Basic if and if with short statement:
x := 10
// Basic if
if x > 5 {
fmt.Println("x is greater than 5")
}
// If with short statement
if y := x * 2; y > 15 {
fmt.Println("y is greater than 15:", y)
}
Switch Statements
Tagless switch, fallthrough example:
day := 3
switch day {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
fallthrough
case 4:
fmt.Println("Thursday")
default:
fmt.Println("Other day")
}
// Tagless switch (like if-else chain)
switch {
case x < 0:
fmt.Println("Negative")
case x == 0:
fmt.Println("Zero")
default:
fmt.Println("Positive")
}
For Loops
Classic, range, and infinite loops:
// Classic for
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// Range over slice
nums := []int{1,2,3}
for index, val := range nums {
fmt.Println(index, val)
}
// Infinite loop
count := 0
for {
fmt.Println("Loop", count)
count++
if count >= 3 { break }
}
Break, Continue, Goto
for i := 0; i < 5; i++ {
if i == 2 {
continue // skip iteration
}
if i == 4 {
break // exit loop
}
fmt.Println(i)
}
// Goto example
label:
fmt.Println("Goto example")
goto label // be careful: infinite if not handled
goto sparingly; prefer structured loops for readability. switch without a tag acts like a cleaner if-else chain.Go Functions & Methods
Basic Functions
Declare functions with optional multiple and named return values:
// Simple function
func add(a, b int) int {
return a + b
}
// Multiple returns
func swap(x, y string) (string, string) {
return y, x
}
// Named returns
func split(total int) (x, y int) {
x = total / 2
y = total - x
return
}
Variadic Functions & Defer
Functions with variable number of arguments and deferred execution:
// Variadic function
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// Defer example
func demo() {
defer fmt.Println("This runs last")
fmt.Println("This runs first")
}
Methods & Receivers
Attach methods to types; use pointer vs value receivers:
type Rectangle struct {
Width, Height float64
}
// Value receiver
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Pointer receiver (can modify original)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
Anonymous Functions & Closures
Functions as values, closures, higher-order functions:
// Anonymous function assigned to variable
greet := func(name string) {
fmt.Println("Hello,", name)
}
greet("Solviyo")
// Closure example
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
posSum := adder()
fmt.Println(posSum(5)) // 5
fmt.Println(posSum(3)) // 8
// Higher-order function
func apply(f func(int) int, value int) int {
return f(value)
}
double := func(x int) int { return x * 2 }
fmt.Println(apply(double, 4)) // 8
Go Generics (Type Parameters)
Basic Generic Functions
Generics allow functions to work with multiple types. Available since Go 1.18+:
// Generic function for swapping two values
func Swap[T any](a, b T) (T, T) {
return b, a
}
x, y := Swap[int](1, 2)
fmt.Println(x, y) // 2 1
s1, s2 := Swap[string]("foo", "bar")
fmt.Println(s1, s2) // bar foo
Generic Types
Define generic types with type parameters:
type Pair[T any] struct {
First, Second T
}
p := Pair[int]{First: 10, Second: 20}
fmt.Println(p.First, p.Second)
Constraints
Use constraints to restrict allowed types:
func SumIntsOrFloats[T int | float64](s []T) T {
var total T
for _, v := range s {
total += v
}
return total
}
Type Parameter & Constraint Table
| Constraint | Description | Example |
|---|---|---|
| any | Accepts any type | T any |
| comparable | Types that support == and != | T comparable |
| Specific types | Restrict to a set of types | T int \| float64 \| string |
Best Practices
- Use generics to reduce code duplication for similar functions/types.
- Prefer simple constraints; avoid overcomplicating type logic.
- Don’t use generics if normal types suffice — clarity first.
Go Arrays, Slices & Maps
Arrays vs Slices
Arrays have fixed length; slices are dynamic and more commonly used.
// Array
var arr [3]int
arr[0] = 1
// Slice (dynamic)
s := []int{1, 2, 3}
s = append(s, 4)
fmt.Println(s) // [1 2 3 4]
// Slice from array
sub := arr[0:2] // slicing
fmt.Println(sub)
Slice Utilities
// make to preallocate slice
numbers := make([]int, 0, 5) // len=0, cap=5
// copy slices
src := []int{1,2,3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst)
Arrays vs Slices Table
| Feature | Array | Slice |
|---|---|---|
| Length | Fixed at compile time | Dynamic, can grow with append |
| Capacity | Same as length | Can be larger than length; grows automatically |
| Memory | Contiguous block, fixed | References underlying array, dynamic allocation |
| Slicing | Not applicable | slice[start:end], shared underlying array |
Maps
Maps store key-value pairs. Keys are unique.
// Create map
ages := map[string]int{"Alice": 25, "Bob": 30}
// Retrieve value
fmt.Println(ages["Alice"]) // 25
// Check existence
v, ok := ages["Charlie"]
fmt.Println(v, ok) // 0 false
// Add or update
ages["Charlie"] = 28
// Delete key
delete(ages, "Bob")
// Iterate (order is random)
for name, age := range ages {
fmt.Println(name, age)
}
Go Structs, Methods & Interfaces
Structs
Define custom types to group related fields:
type Person struct {
Name string
Age int
}
// Struct literal
p := Person{Name: "Alice", Age: 30}
// Access fields
fmt.Println(p.Name, p.Age)
// Embedding (composition)
type Employee struct {
Person
Position string
}
e := Employee{
Person: Person{Name: "Bob", Age: 25},
Position: "Developer",
}
fmt.Println(e.Name, e.Position) // inherited field
JSON Tags Example
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
Methods
Attach behavior to structs:
// Value receiver
func (p Person) Greet() string {
return "Hello, " + p.Name
}
// Pointer receiver (can modify fields)
func (p *Person) HaveBirthday() {
p.Age++
}
alice := Person{Name: "Alice", Age: 30}
fmt.Println(alice.Greet())
alice.HaveBirthday()
fmt.Println(alice.Age) // 31
Interfaces
Define behavior implicitly; any type implementing methods satisfies the interface:
type Greeter interface {
Greet() string
}
func sayHello(g Greeter) {
fmt.Println(g.Greet())
}
sayHello(alice) // Person implements Greeter
// Empty interface
var anyValue interface{}
anyValue = 42
anyValue = "Solviyo"
Common Go Interfaces Table
| Interface | Description | Example Usage |
|---|---|---|
| io.Reader | Anything that can read data | file.Read(p []byte) |
| io.Writer | Anything that can write data | os.Stdout.Write([]byte("Hello")) |
| fmt.Stringer | Types that can return string representation | func (p Person) String() string |
| error | Represents errors in Go | return errors.New("something went wrong") |
Best Practices
- Keep interfaces small; prefer many small interfaces over one large one.
- Use composition (embedding) instead of deep inheritance hierarchies.
- Rely on implicit implementation rather than explicit declarations.
Go Pointers & Memory Model
Pointer Basics
Use pointers to reference memory locations:
// Declare a variable
x := 42
// Pointer to x
ptr := &x
fmt.Println(*ptr) // Dereference, prints 42
// Modify value via pointer
*ptr = 100
fmt.Println(x) // 100
Pointers in Functions
Pass by reference using pointers:
func increment(n *int) {
*n++
}
val := 10
increment(&val)
fmt.Println(val) // 11
Pointers with Methods
Use pointer receivers to modify struct fields:
type Counter struct {
Count int
}
func (c *Counter) Increase() {
c.Count++
}
ctr := Counter{}
ctr.Increase()
fmt.Println(ctr.Count) // 1
Memory Allocation & Escape Analysis
Brief notes:
- `new(Type)` allocates zeroed memory and returns a pointer.
- Local variables may escape to heap if referenced outside function (Go escape analysis).
- Pointers help reduce copies for large structs and slices.
Pointer Operators Table
| Operator | Usage | Example |
|---|---|---|
| & | Address-of operator | ptr := &x |
| * | Dereference operator | fmt.Println(*ptr) |
| new(Type) | Allocates memory and returns pointer | p := new(int) |
Go Error Handling & Best Practices
Basic Error Handling
Go uses the built-in error type. Return errors from functions:
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
Error Wrapping
Wrap errors to preserve context using %w:
func readFile(path string) error {
_, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read %s: %w", path, err)
}
return nil
}
// Check specific error
if errors.Is(err, os.ErrNotExist) {
fmt.Println("File does not exist")
}
Panic, Recover & Defer
Use panic for unrecoverable errors; recover can catch panics:
func safeDivide(a, b int) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
if b == 0 {
panic("division by zero")
}
fmt.Println("Result:", a/b)
}
safeDivide(10, 0)
Error Utilities Table
| Function | Purpose | Example |
|---|---|---|
| errors.New | Create a simple error | errors.New("something went wrong") |
| fmt.Errorf | Format and wrap errors | fmt.Errorf("context: %w", err) |
| errors.Is | Check error equality | errors.Is(err, os.ErrNotExist) |
| errors.As | Check and cast error type | errors.As(err, &pathErr) |
| errors.Join | Combine multiple errors (Go 1.20+) | errors.Join(err1, err2) |
Best Practices
- Return errors instead of panicking for recoverable situations.
- Use
defer+recoveronly for top-level recovery, not normal flow control. - Log errors at the boundary (main function or handler), pass context with wrapping.
- Small, descriptive error messages improve debugging and API clarity.
errors.Is/errors.As for precise handling.Go Concurrency — Goroutines, Channels & Patterns
Goroutines
Goroutines are lightweight threads managed by the Go runtime. Launch a goroutine using the go keyword. They run concurrently, allowing efficient scaling without heavy OS threads.
func sayHello() {
fmt.Println("Hello from Goroutine")
}
// Launch goroutine
go sayHello()
// Wait for goroutines using sync.WaitGroup
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("Task completed")
}()
wg.Wait()
Channels
Channels provide a safe way for goroutines to communicate. They can be unbuffered or buffered.
// Unbuffered channel
ch := make(chan int)
go func() { ch <- 42 }()
val := <-ch
fmt.Println(val) // 42
// Buffered channel
buf := make(chan string, 2)
buf <- "foo"
buf <- "bar"
fmt.Println(<-buf, <-buf)
// Close channel and range over values
close(buf)
for v := range buf {
fmt.Println(v)
}
Channel Types
| Channel Type | Description | Example |
|---|---|---|
| Unbuffered | Sender blocks until receiver is ready | ch := make(chan int) |
| Buffered | Sender can send without blocking until buffer is full | ch := make(chan int, 5) |
| Closed | No more values can be sent; receivers get zero value | close(ch) |
Select Statement & Timeouts
The select statement allows waiting on multiple channel operations simultaneously. It is also used for non-blocking communication and timeouts.
select {
case msg := <-ch:
fmt.Println("Received", msg)
case <-time.After(2 * time.Second):
fmt.Println("Timeout reached")
default:
fmt.Println("No channel activity")
}
Select Statement Patterns
| Pattern | Description | Example |
|---|---|---|
| Receive | Wait for value from channel | case msg := <-ch: |
| Timeout | Exit if channel doesn’t respond in time | case <-time.After(2 * time.Second): |
| Default | Non-blocking select | default: |
Synchronization Primitives
Use synchronization primitives when channels are insufficient for shared memory access.
var mu sync.Mutex
counter := 0
// Protect shared resource
mu.Lock()
counter++
mu.Unlock()
// Atomic operations
import "sync/atomic"
atomic.AddInt32(&counter32, 1)
Synchronization Primitives Table
| Primitive | Purpose | Example |
|---|---|---|
| sync.Mutex | Lock/unlock shared memory | mu.Lock(); counter++; mu.Unlock() |
| sync.RWMutex | Read-write lock for concurrent reads | rw.RLock(); ...; rw.RUnlock() |
| sync/atomic | Atomic operations on primitives | atomic.AddInt32(&counter32, 1) |
Common Concurrency Patterns
- Worker Pools: Multiple goroutines process jobs from a channel efficiently.
- Pipeline Pattern: Chain goroutines to process streams step by step.
- Worker per CPU: One goroutine per CPU core for CPU-bound tasks.
- Rate Limiting: Limit concurrency using buffered channels or
time.Ticker. - Context Cancellation: Use
context.Contextto stop goroutines gracefully and avoid leaks.
Concurrency Patterns Table
| Pattern | Description | Example / Notes |
|---|---|---|
| Worker Pool | Multiple goroutines process jobs from a channel | jobs := make(chan Job, 10) |
| Pipeline | Sequential data processing in stages | Stage1 -> Stage2 -> Stage3 via channels |
| Context Cancellation | Stop goroutines gracefully | ctx, cancel := context.WithCancel(parentCtx) |
| Rate Limiting | Control number of concurrent operations | Buffered channels or time.Ticker |
Tools & Best Practices
- Detect race conditions:
go test -race - Avoid goroutine leaks: always close channels or cancel context.
- Prefer channels for communication; use mutexes only for shared memory.
- Keep goroutines short-lived; avoid blocking operations without timeout.
- Use
selectwithtime.Afterand default cases for non-blocking operations.
Go Packages, Modules & Dependency Management
Module Lifecycle
Modules are the standard way to manage dependencies in modern Go. Use go mod commands to initialize, tidy, and manage dependencies.
# Initialize a new module
go mod init github.com/username/myproject
# Tidy dependencies (add missing, remove unused)
go mod tidy
# Add or update a dependency
go get github.com/gin-gonic/gin@v1.9.0
Semantic Import Versioning & Replace
For modules with major version v2+, the import path must include the version suffix. Use replace directive for local development:
// go.mod example
module github.com/username/myproject/v2
go 1.21
require github.com/gin-gonic/gin v1.9.0
// Replace local copy for testing
replace github.com/gin-gonic/gin => ../gin
GOPROXY, Caching & Vendoring
Go modules use a proxy and cache for reliable builds. Vendoring copies dependencies locally for reproducible builds:
# Set proxy
export GOPROXY=https://proxy.golang.org,direct
# Verify module cache
go env GOMODCACHE
# Create vendor directory
go mod vendor
Module Commands Table
| Command | Purpose | Example |
|---|---|---|
| go mod init | Create a new module | go mod init github.com/username/myproject |
| go mod tidy | Add missing, remove unused dependencies | go mod tidy |
| go get | Add or update dependency | go get github.com/gin-gonic/gin@v1.9.0 |
| go mod vendor | Copy dependencies locally | go mod vendor |
| replace | Use local module path instead of remote | replace github.com/gin-gonic/gin => ../gin |
go mod tidy after adding or removing dependencies.Go Standard Library Highlights — Practical Picks
net/http — Quick Server & Client
Build HTTP servers and clients quickly with the standard library.
// Simple HTTP server
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Solviyo!")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
// Simple HTTP client
resp, err := http.Get("http://localhost:8080")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
encoding/json — Marshal & Unmarshal
Convert structs to/from JSON with struct tags:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
user := User{Name: "Alice", Email: "alice@example.com"}
// Marshal to JSON
data, _ := json.Marshal(user)
fmt.Println(string(data))
// Unmarshal from JSON
var u User
_ = json.Unmarshal(data, &u)
fmt.Println(u.Name, u.Email)
File & Stream Handling — io, bufio, os
Reading & writing files efficiently:
import (
"bufio"
"fmt"
"io"
"os"
)
// Read file line by line
file, _ := os.Open("input.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
// Write file
out, _ := os.Create("output.txt")
defer out.Close()
out.WriteString("Hello Solviyo!\n")
time & context Utilities
Use time for durations, sleep, and timestamps; context for cancellation and deadlines:
import (
"context"
"fmt"
"time"
)
// Timeout with context
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
select {
case <-time.After(3 * time.Second):
fmt.Println("Task done")
case <-ctx.Done():
fmt.Println("Timeout reached:", ctx.Err())
}
Standard Library Quick Reference Table
| Package | Use Case | Example |
|---|---|---|
| net/http | HTTP server & client | http.HandleFunc("/", handler) |
| encoding/json | JSON marshal/unmarshal | json.Marshal(u), json.Unmarshal(data, &u) |
| io, bufio, os | File and stream handling | bufio.NewScanner(file), os.Create("out.txt") |
| time | Durations, sleep, timestamps | time.Sleep(2*time.Second) |
| context | Cancellation, deadlines | context.WithTimeout(parentCtx, 2*time.Second) |
Go File I/O & Networking Examples
File I/O — Read & Write
Handle files efficiently using os and bufio. Examples include reading line by line, writing, and streaming large files.
import (
"bufio"
"fmt"
"os"
)
// Reading a file line by line
file, _ := os.Open("input.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
// Writing to a file
out, _ := os.Create("output.txt")
defer out.Close()
out.WriteString("Hello Solviyo!\n")
// Streaming large files
in, _ := os.Open("largefile.dat")
defer in.Close()
outFile, _ := os.Create("copy.dat")
defer outFile.Close()
buf := make([]byte, 1024*4) // 4KB buffer
for {
n, err := in.Read(buf)
if n > 0 {
outFile.Write(buf[:n])
}
if err != nil {
break
}
}
Networking — Basic HTTP Server
Create a minimal HTTP server with routing and handlers.
import (
"fmt"
"log"
"net/http"
)
// Handler function
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Solviyo!")
}
// Custom route
func aboutHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "About Solviyo")
}
func main() {
http.HandleFunc("/", helloHandler)
http.HandleFunc("/about", aboutHandler)
log.Println("Server running at :8080")
http.ListenAndServe(":8080", nil)
}
File & Networking Quick Reference Table
| Task | Package / Function | Example |
|---|---|---|
| Read file line by line | os + bufio | scanner := bufio.NewScanner(file) |
| Write to file | os.File.WriteString | out.WriteString("Hello") |
| Stream large files | os.File.Read | buf := make([]byte, 4096) |
| Basic HTTP server | net/http | http.HandleFunc("/", handler) |
| Routing | http.HandleFunc | http.HandleFunc("/about", aboutHandler) |
Go Testing, Benchmarking & Quality Tools
Unit Testing Basics
Use go test to run tests. Table-driven tests are common in Go for multiple input/output cases.
import "testing"
// Function to test
func Add(a, b int) int {
return a + b
}
// Table-driven test
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"1+2", 1, 2, 3},
{"5+7", 5, 7, 12},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.want {
t.Errorf("Add(%d,%d) = %d, want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
Benchmarking
Measure performance of functions using testing.B:
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Add(100, 200)
}
}
// Run benchmark:
// go test -bench=.
Profiling with pprof
Capture CPU and memory profiles:
import (
"net/http"
_ "net/http/pprof"
)
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// your application code
}
Quality Tools Quick Reference
| Tool | Purpose | Example / Command |
|---|---|---|
| go vet | Check code correctness and common mistakes | go vet ./... |
| gofmt | Automatically format code | gofmt -w main.go |
| golangci-lint | Run multiple linters in one tool | golangci-lint run |
| delve | Debugger for Go | dlv debug main.go |
| pprof | CPU / memory profiling | go tool pprof cpu.prof |
| testing.B | Benchmark functions | go test -bench=. |
Go Performance & Profiling Tips
CPU & Memory Profiling with pprof
Use pprof to analyze performance bottlenecks:
import (
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// Your application code
}
// Run the program and use:
// go tool pprof http://localhost:6060/debug/pprof/profile
// go tool pprof http://localhost:6060/debug/pprof/heap
Memory Optimization
Reduce allocations and reuse buffers efficiently:
import "sync"
var bufPool = sync.Pool{
New: func() interface{} {
return make([]byte, 4096)
},
}
func processData(data []byte) {
buf := bufPool.Get().([]byte)
defer bufPool.Put(buf)
// use buf for temporary processing
}
Benchmarking Patterns
Use testing.B to identify slow functions and interpret results:
func BenchmarkProcessData(b *testing.B) {
data := make([]byte, 1024)
for i := 0; i < b.N; i++ {
processData(data)
}
}
// Run with:
// go test -bench=.
Performance Quick Reference Table
| Task | Tool / Pattern | Example / Notes |
|---|---|---|
| CPU profiling | pprof | go tool pprof http://localhost:6060/debug/pprof/profile |
| Memory profiling | pprof | go tool pprof http://localhost:6060/debug/pprof/heap |
| Reduce allocations | sync.Pool | buf := bufPool.Get() |
| Benchmark functions | testing.B | go test -bench=. |
| Buffer reuse | slice reuse | Use pooled slices instead of new allocations |
Go Build, Cross-compilation & Deployment
Cross-compilation
Go makes it easy to build binaries for other platforms using GOOS and GOARCH environment variables.
# Build Linux binary on macOS
GOOS=linux GOARCH=amd64 go build -o myapp-linux
# Build Windows binary on Linux
GOOS=windows GOARCH=386 go build -o myapp.exe
# Check available architectures
go tool dist list
Static Binaries
Create self-contained binaries for deployment:
# Static binary for Linux
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags="-s -w" -o myapp
Building & Running with Docker
Use multi-stage Docker builds for small, portable images:
# Stage 1: Build
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Stage 2: Minimal image
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
CI/CD Snippet Example
GitHub Actions example to build and test:
name: Go CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.21
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
Build & Deployment Quick Reference Table
| Task | Command / Tool | Notes |
|---|---|---|
| Cross-compile | GOOS & GOARCH | GOOS=linux GOARCH=amd64 go build |
| Static binary | CGO_ENABLED=0 | go build -a -ldflags="-s -w" |
| Docker build | Multi-stage Dockerfile | Use builder + minimal runtime image |
| CI/CD | GitHub Actions | Set up Go, build & test automatically |
Advanced Go Topics — Quick Reference
Reflection (`reflect`)
Use reflection to inspect types and values at runtime. Use sparingly — it can be slower and less safe.
import (
"fmt"
"reflect"
)
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
fmt.Println("value:", reflect.ValueOf(x))
cgo — Interoperability with C
Allows calling C code from Go. Useful but adds complexity and may reduce portability.
/*
#include
#include
*/
import "C"
func main() {
C.puts(C.CString("Hello from C via Go!"))
}
Build Tags & Conditional Compilation
Use build tags to include/exclude files for specific platforms or conditions.
// +build linux
package main
func main() {
println("This file compiles only on Linux")
}
Embed Files (`embed` package)
Embed static files directly into your binary using go:embed:
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var helloText string
func main() {
fmt.Println(helloText)
}
Advanced Topics Quick Reference Table
| Feature | Purpose | Example |
|---|---|---|
| Reflection | Inspect types & values at runtime | reflect.TypeOf(x), reflect.ValueOf(x) |
| cgo | Call C functions from Go | C.puts(C.CString("Hello")) |
| Build Tags | Conditional compilation for platforms | // +build linux |
| Embed | Include files in binary | //go:embed hello.txt |
Go Security & Best Practices
Input Validation & Sanitization
Validate and sanitize inputs to prevent injection and unexpected behavior. Use proper escaping for HTML or URL contexts.
package main
import (
"fmt"
"html"
"net/url"
)
// Escape for HTML output
func escapeForHTML(s string) string {
return html.EscapeString(s)
}
// Escape for URL/query parameter
func escapeForURL(s string) string {
return url.QueryEscape(s)
}
func main() {
raw := `Hello & "special" chars?`
fmt.Println("HTML escaped:", escapeForHTML(raw))
fmt.Println("URL escaped:", escapeForURL(raw))
}
Secure JSON Handling
Use concrete structs for JSON input and avoid unmarshalling into map[string]interface{} unless you explicitly need dynamic schemas.
package main
import (
"encoding/json"
"log"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
data := []byte(`{"name":"Alice","email":"alice@example.com"}`)
var u User
if err := json.Unmarshal(data, &u); err != nil {
log.Fatal("invalid JSON:", err)
}
log.Printf("User: %#v\n", u)
}
TLS & Secure Communication
Use HTTPS/TLS in production. For local testing, use self-signed certs but avoid sending sensitive data over plain HTTP.
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello — secure server"))
})
// Use ListenAndServeTLS with valid cert/key in production.
log.Println("Starting secure server on :8443")
log.Fatal(http.ListenAndServeTLS(":8443", "server.crt", "server.key", nil))
}
Secrets Management
Do not hardcode secrets. Read them from environment variables or use a secrets manager.
package main
import (
"fmt"
"os"
)
func main() {
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
fmt.Println("WARNING: API_KEY not set")
// In production, fail fast or use secure default handling
} else {
fmt.Println("API key loaded from environment")
}
}
Preventing Unsafe DOM Injection (Client-side note)
If your Go backend returns user-controlled data to a web page, always ensure the frontend inserts it safely:
// BAD: vulnerable to executing HTML or scripts
element.innerHTML = userProvidedString;
// GOOD: render as plain text (safe)
element.textContent = userProvidedString;
Security Quick Reference Table
| Task | Practice | Notes |
|---|---|---|
| Input sanitization | html.EscapeString, url.QueryEscape |
Escape for the specific output context (HTML vs URL). |
| JSON handling | Use strict structs + json.Unmarshal |
Avoid generic maps unless intentionally required. |
| TLS / HTTPS | http.ListenAndServeTLS |
Always use TLS in production; protect certificates. |
| Secrets | Environment variables, vaults | Never commit keys or passwords to source control. |
textContent, not innerHTML) to prevent XSS.Common Go Commands — Quick Reference
This table summarizes the most frequently used Go commands for daily development, building, testing, and formatting.
| Command | Description | Example Usage |
|---|---|---|
| go run | Compile and run Go files in one step | go run main.go |
| go build | Compile Go code into a binary | go build -o myapp main.go |
| go test | Run unit tests | go test ./... |
| go fmt | Automatically format Go source code | go fmt ./... |
| go vet | Analyze code for potential errors or suspicious constructs | go vet ./... |
| go install | Compile and install a package or binary to GOPATH/bin | go install github.com/user/myapp@latest |
| go mod init | Initialize a new module in the project | go mod init github.com/user/myproject |
| go mod tidy | Clean up module dependencies | go mod tidy |
| go get | Add or update a dependency | go get github.com/pkg/errors |
Quick Patterns & Idioms — Go Cheat Cards
This section highlights common idiomatic Go patterns and best practices to write clean, maintainable, and idiomatic code.
Common Idioms
- Zero Value: Go variables are automatically initialized to their zero value (0, "", false, nil). Take advantage of this instead of explicit initialization.
- Small Interfaces: Prefer defining small, focused interfaces rather than large ones.
- Error Handling Idiom: Return
errorand handle it immediately withif err != nil. - Slices over Arrays: Use slices for flexible, resizable lists.
- Defer for Cleanup: Use
deferto close files, connections, or release resources. - For Range Loops: Use
for i, v := range collectioninstead of traditional loops when iterating over slices, maps, or channels. - Composition over Inheritance: Prefer embedding structs instead of relying on inheritance.
- Minimalistic Error Logging: Log only essential information, avoid panics in production unless unavoidable.
Quick Reference Table
| Pattern | Description | Example |
|---|---|---|
| Zero Value | Default initialization | var count int // count == 0 |
| Small Interfaces | Keep interfaces focused | type Reader interface { Read(p []byte) (n int, err error) } |
| Error Handling | Idiomatic Go error check | if err != nil { return err } |
| Slices over Arrays | Flexible lists | nums := []int{1,2,3} |
| Defer | Automatic cleanup | defer file.Close() |
| Composition | Embed instead of inherit | type Logger struct { io.Writer } |
Conclusion & Further Reading
Congratulations! You’ve gone through the ultimate Go (Golang) cheat sheet. By now, you should have a solid understanding of Go syntax, data structures, concurrency patterns, modules, testing, and advanced topics. Remember, the best way to master Go is through practice — build projects, experiment with goroutines, and explore the standard library.