Go (Golang) Cheatsheet

Complete reference guide for Go programming language - Syntax, Concurrency, Standard Library, and Best Practices

Basics & Syntax

Hello World

package main

import "fmt"

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

Basic Go program structure. Every executable Go program must have a main package and main function.

Package Declaration

// Declare package name
package main

// Import multiple packages
import (
  "fmt"
  "math"
  "strings"
)

Package declaration and imports. Use grouped import syntax for cleaner code.

Variable Declaration

// Explicit type declaration
var name string = "Go"

// Type inference
var version = "1.21"

// Short declaration (inside functions)
count := 10

// Multiple variables
var x, y int = 1, 2
a, b := "hello", "world"

Different ways to declare variables in Go. Short declaration (:=) can only be used inside functions.

Constants

// Basic constant
const Pi = 3.14159

// Typed constant
const MaxSize int = 1024

// Multiple constants
const (
  StatusOK = 200
  StatusNotFound = 404
)

// Iota for enumerated constants
const (
  Red = iota // 0
  Green // 1
  Blue // 2
)

Constants are immutable values. Iota creates incrementing constants starting from 0.

Comments

// Single line comment

/*
Multi-line
comment
*/


// Documentation comment (for godoc)
// Package math provides basic constants
// and mathematical functions.

Go supports single-line and multi-line comments. Comments starting with // are used by godoc for documentation.

Zero Values

var i int // 0
var f float64 // 0.0
var b bool // false
var s string // ""
var p *int // nil
var sl []int // nil
var m map[string]int // nil

Default values for uninitialized variables in Go. This prevents undefined behavior.

Data Types

Basic Types

// Integer types
var i int // Platform-dependent (32 or 64 bits)
var i8 int8 // -128 to 127
var i16 int16 // -32768 to 32767
var i32 int32 // -2147483648 to 2147483647
var i64 int64 // Large range

// Unsigned integers
var u uint // Platform-dependent
var u8 uint8 // 0 to 255 (byte alias)
var u16 uint16
var u32 uint32
var u64 uint64

// Floating point
var f32 float32
var f64 float64

// Complex numbers
var c64 complex64
var c128 complex128

Go has a rich set of numeric types with specific sizes for precise memory usage.

Strings & Runes

// String type (immutable)
var s string = "Hello, 世界"

// Rune (int32 alias for Unicode code points)
var r rune = 'A'
var r2 rune = '世'

// String operations
len := len(s) // Length in bytes
chars := []rune(s) // Convert to rune slice
sub := s[0:5] // Slicing
concat := s + "!" // Concatenation
contains := strings.Contains(s, "世界")

Strings are immutable byte slices. Runes represent Unicode code points. Use string package for manipulation.

Booleans

var isTrue bool = true
var isFalse bool = false

// Logical operations
result1 := true && false // AND: false
result2 := true || false // OR: true
result3 := !true // NOT: false

// Comparison operators
equal := (5 == 5) // true
notEqual := (5 != 3) // true
greater := (10 > 5) // true
less := (3 < 2) // false

Boolean type with logical operators (&&, ||, !) and comparison operators (==, !=, <, >, <=, >=).

Pointers

var x int = 42
var p *int = &x // Address of x

fmt.Println(*p) // Dereference: 42

*p = 100 // Modify through pointer
fmt.Println(x) // 100

// new() allocates zeroed memory
ptr := new(int)
*ptr = 10

Pointers hold memory addresses. Use & to get address, * to dereference. Go has no pointer arithmetic.

Type Conversions

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

// String conversions
s := string(65) // "A" (rune to string)
str := fmt.Sprintf("%d", i) // Int to string

// strconv package for parsing
num, err := strconv.Atoi("123")
str2 := strconv.Itoa(456)

Go requires explicit type conversions. Use T(v) syntax. strconv package handles string conversions.

Type Aliases & Definitions

// Type alias (same type)
type MyInt = int
var a int = 5
var b MyInt = a // OK, same type

// Type definition (new type)
type MyNewInt int
var c int = 5
// var d MyNewInt = c // Error: type mismatch
var d MyNewInt = MyNewInt(c) // OK with conversion

// Commonly used for readability
type ID int64
type Currency float64

Type aliases create alternative names for existing types. Type definitions create distinct new types.

Control Flow

If Statements

// Basic if
if x > 10 {
  fmt.Println("x is greater than 10")
}

// If with initialization
if val := computeValue(); val > 100 {
  fmt.Println("Large value:", val)
} else {
  fmt.Println("Small value:", val)
}

// If-else chain
if score >= 90 {
  grade = "A"
} else if score >= 80 {
  grade = "B"
} else {
  grade = "C"
}

If statements can include initialization. Variables declared in if are scoped to the if block.

For Loops

// Traditional 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 with condition
  if condition {
    break
  }
}

// Continue statement
for i := 0; i < 10; i++ {
  if i%2 == 0 {
    continue // Skip even numbers
  }
  fmt.Println(i)
}

Go has only one loop construct: for. It can be used as traditional for, while, or infinite loop.

Range Loops

// Range over slice/array
nums := []int{2, 3, 4}
for i, num := range nums {
  fmt.Printf("index %d: value %d\n", i, num)
}

// Range over map
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
  fmt.Println(k, v)
}

// Range over string (runes)
for i, r := range "Hello" {
  fmt.Printf("%d: %c\n", i, r)
}

// Ignore index/value
for _, num := range nums {
  // Only use value
}
for i := range nums {
  // Only use index
}

Range iterates over elements in slices, arrays, maps, strings, and channels. Returns index/key and value.

Switch Statements

// Basic switch
switch os := runtime.GOOS; os {
case "darwin":
  fmt.Println("macOS")
case "linux":
  fmt.Println("Linux")
default:
  fmt.Println(os)
}

// Switch without expression (if-else alternative)
switch {
case hour < 12:
  fmt.Println("Good morning!")
case hour < 17:
  fmt.Println("Good afternoon!")
default:
  fmt.Println("Good evening!")
}

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

Switch in Go is more flexible than in other languages. Cases don't fall through by default (use fallthrough keyword).

Defer Statement

// Basic defer
func readFile() {
  f, err := os.Open("file.txt")
  if err != nil {
    return
  }
  defer f.Close() // Executes when function returns
  // Read file contents...
}

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

// Defer with arguments evaluation
func deferExample() {
  i := 1
  defer fmt.Println(i) // Prints 1, not 2
  i = 2
  return
}

Defer schedules a function call to run when the surrounding function returns. Useful for cleanup tasks.

Panic & Recover

// Panic stops normal execution
func mayPanic() {
  panic("something went wrong")
}

// Recover captures panic
func safeCall() {
  defer func() {
    if r := recover(); r != nil {
      fmt.Println("Recovered from panic:", r)
    }
  }()
  mayPanic()
  fmt.Println("This won't be printed")
}

// Built-in panics
var s []int
fmt.Println(s[0]) // Panic: runtime error: index out of range

var m map[string]int
m["key"] = 1 // Panic: assignment to entry in nil map

Panic stops execution and unwinds the stack. Recover can capture panics in deferred functions. Use sparingly.

Functions

Basic Functions

// Function with parameters and return value
func add(x int, y int) int {
  return x + y
}

// Same type parameters can be grouped
func multiply(x, y int) int {
  return x * y
}

// Multiple return values
func swap(x, y string) (string, string) {
  return y, x
}

// Named return values
func split(sum int) (x, y int) {
  x = sum * 4 / 9
  y = sum - x
  return // "naked" return
}

Functions can have multiple parameters and return values. Named returns act as variables defined at top of function.

Variadic Functions

// Variadic function (variable number of args)
func sum(nums ...int) int {
  total := 0
  for _, num := range nums {
    total += num
  }
  return total
}

// Calling variadic functions
result1 := sum(1, 2, 3) // 6
result2 := sum(1, 2, 3, 4, 5) // 15

// Pass slice to variadic function
nums := []int{1, 2, 3, 4}
result3 := sum(nums...)

// Variadic with other parameters
func join(sep string, strs ...string) string {
  return strings.Join(strs, sep)
}

Variadic functions accept zero or more arguments of a specified type. Use ... before type in parameter list.

Function Values

// Functions as values
func add(a, b int) int { return a + b }
func multiply(a, b int) int { return a * b }

// Assign function to variable
var operation func(int, int) int
operation = add
result := operation(3, 4) // 7

operation = multiply
result = operation(3, 4) // 12

// Function as parameter
func compute(x, y int, op func(int, int) int) int {
  return op(x, y)
}

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

Functions are first-class values in Go. They can be assigned to variables, passed as arguments, and returned from functions.

Closures

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

// Using the closure
next := counter()
fmt.Println(next()) // 1
fmt.Println(next()) // 2
fmt.Println(next()) // 3

// Each closure has its own state
anotherCounter := counter()
fmt.Println(anotherCounter()) // 1

// Practical closure: Adder
func adder(start int) func(int) int {
  return func(x int) int {
    start += x
    return start
  }
}

Closures are functions that reference variables from outside their body. They encapsulate state.

Methods

// Define a type
type Rectangle struct {
  Width, Height float64
}

// Method with value receiver
func (r Rectangle) Area() float64 {
  return r.Width * r.Height
}

// Method with pointer receiver
func (r *Rectangle) Scale(factor float64) {
  r.Width *= factor
  r.Height *= factor
}

// Using methods
rect := Rectangle{Width: 10, Height: 5}
area := rect.Area() // 50
rect.Scale(2) // Width=20, Height=10

// Method on non-struct type
type MyInt int

func (m MyInt) Double() MyInt {
  return m * 2
}

Methods are functions with a receiver argument. Pointer receivers can modify the value, value receivers cannot.

init() Function

// Each file can have init() functions
func init() {
  fmt.Println("Package initialization")
}

// Multiple init() functions execute in order
func init() {
  fmt.Println("Second initialization")
}

func main() {
  fmt.Println("Main function")
}
// Output:
// Package initialization
// Second initialization
// Main function


// Common use cases:
var config string

func init() {
  // Initialize package variables
  config = os.Getenv("APP_CONFIG")
  if config == "" {
    config = "default"
  }
}

init() functions are automatically executed before main(). Each package can have multiple init() functions.

Structs & Interfaces

Structs

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

// Create struct instances
var p1 Person // Zero value
p2 := Person{"Alice", 30} // Literal
p3 := Person{Name: "Bob", Age: 25} // Field names
p4 := &Person{"Charlie", 35} // Pointer

// Access fields
p1.Name = "David"
age := p2.Age

// Anonymous structs
point := struct {
  X, Y int
}{10, 20}

// Nested structs
type Address struct {
  City, Country string
}
type Employee struct {
  Person
  Address Address
  Salary float64
}

Structs are collections of fields. They can be nested and support anonymous structs for one-time use.

Struct Tags

// Struct with tags
type User struct {
  ID int `json:"id" db:"user_id"`
  Username string `json:"username" validate:"required"`
  Email string `json:"email,omitempty"`
  Password string `json:"-"` // Never marshal
  CreatedAt time.Time `json:"created_at"`
}

// Using tags with encoding/json
func example() {
  user := User{
    ID: 1,
    Username: "johndoe",
    Email: "",
  }
  
  jsonData, err := json.Marshal(user)
  // {"id":1,"username":"johndoe"}
  // Email omitted due to omitempty
}

// Reading tags with reflection
func printTags() {
  t := reflect.TypeOf(User{})
  field := t.Field(0)
  tag := field.Tag.Get("json")
  fmt.Println(tag) // "id"
}

Struct tags are metadata strings attached to struct fields, commonly used by encoding packages and validators.

Interfaces

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

// Implement interface implicitly
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
func printArea(s Shape) {
  fmt.Println("Area:", s.Area())
}

rect := Rectangle{Width: 10, Height: 5}
printArea(rect) // Area: 50

// Empty interface (any type)
func describe(i interface{}) {
  fmt.Printf("Type: %T, Value: %v\n", i, i)
}

Interfaces define method sets. Types implement interfaces implicitly by implementing all methods. Empty interface (interface{}) accepts any value.

Type Assertions

// Type assertion
var i interface{} = "hello"

s := i.(string)
fmt.Println(s) // hello

// Type assertion with ok check
s, ok := i.(string)
if ok {
  fmt.Println("String:", s)
} else {
  fmt.Println("Not a string")
}

// Failed assertion causes panic
// f := i.(float64) // panic!

// Practical example
func processValue(val interface{}) {
  switch v := val.(type) {
  case int:
    fmt.Println("Integer:", v*2)
  case string:
    fmt.Println("String:", strings.ToUpper(v))
  default:
    fmt.Println("Unknown type")
  }
}

Type assertions extract concrete values from interfaces. Use the "comma ok" idiom to avoid panics with failed assertions.

Embedded Types

// Embedded struct (composition)
type Person struct {
  Name string
  Age int
}

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

// Using embedded type
emp := Employee{
  Person: Person{Name: "Alice", Age: 30},
  Department: "Engineering",
  Salary: 75000,
}

// Access embedded fields directly
fmt.Println(emp.Name) // Alice (promoted field)
fmt.Println(emp.Person.Age) // 30 (explicit)

// Embedded interfaces
type Reader interface {
  Read([]byte) (int, error)
}

type Writer interface {
  Write([]byte) (int, error)
}

type ReadWriter interface {
  Reader
  Writer
}

Embedded types allow composition. Fields and methods of embedded types are promoted to the outer type (but can be shadowed).

Stringer Interface

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

// Custom type implementing Stringer
type Point struct {
  X, Y int
}

func (p Point) String() string {
  return fmt.Sprintf("Point(%d, %d)", p.X, p.Y)
}

// Using the Stringer
p := Point{X: 10, Y: 20}
fmt.Println(p) // Prints: Point(10, 20)

// Another example with enum-like type
type Color int

const (
  Red Color = iota
  Green
  Blue
)

func (c Color) String() string {
  switch c {
  case Red:
    return "Red"
  case Green:
    return "Green"
  case Blue:
    return "Blue"
  default:
    return "Unknown"
  }
}

The Stringer interface (from fmt package) allows custom string representation for types. fmt.Println uses this automatically.

Concurrency

Goroutines

// Start a goroutine
func say(s string) {
  for i := 0; i < 5; i++ {
    time.Sleep(100 * time.Millisecond)
    fmt.Println(s)
  }
}

func main() {
  go say("world") // New goroutine
  say("hello") // Current goroutine
}

// Anonymous function goroutine
go func(msg string) {
  fmt.Println(msg)
}("starting")

// Goroutine with closure
for i := 0; i < 5; i++ {
  go func(n int) {
    fmt.Println(n)
  }(i)
  // Pass i as parameter to avoid closure issues
}

Goroutines are lightweight threads managed by the Go runtime. Use 'go' keyword to start a new goroutine.

Channels

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

// Send to channel (blocks until received)
go func() {
  ch <- 42
}()

// Receive from channel (blocks until sent)
value := <-ch
fmt.Println(value) // 42

// Buffered channel
buffered := make(chan string, 2)
buffered <- "first"
buffered <- "second"
// buffered <- "third" // Would block (buffer full)

fmt.Println(<-buffered) // first
fmt.Println(<-buffered) // second

// Channel direction (in function signatures)
func producer(ch chan<- int) { // Send-only
  ch <- 1
}
func consumer(ch <-chan int) { // Receive-only
  value := <-ch
}

Channels are typed conduits for Goroutine communication. Can be unbuffered (synchronous) or buffered (asynchronous).

Select Statement

// Select with multiple channels
func worker(ch1, ch2 chan string) {
  for {
    select {
    case msg1 := <-ch1:
      fmt.Println("From ch1:", msg1)
    case msg2 := <-ch2:
      fmt.Println("From ch2:", msg2)
    case <-time.After(1 * time.Second):
      fmt.Println("timeout")
      return
    }
  }
}

// Default case (non-blocking)
select {
case msg := <-ch:
  fmt.Println("Received:", msg)
default:
  fmt.Println("No message received")
}

// Select for sending
select {
case ch <- value:
  fmt.Println("Sent value")
case <-time.After(100 * time.Millisecond):
  fmt.Println("Send timeout")
}

Select waits on multiple channel operations. It blocks until one of its cases can run, then executes that case.

Sync Package

// WaitGroup for goroutine synchronization
func worker(id int, wg *sync.WaitGroup) {
  defer wg.Done()
  fmt.Printf("Worker %d starting\n", id)
  time.Sleep(time.Second)
  fmt.Printf("Worker %d done\n", id)
}

func main() {
  var wg sync.WaitGroup
  for i := 1; i <= 5; i++ {
    wg.Add(1)
    go worker(i, &wg)
  }
  wg.Wait()
}

// Mutex for shared data
type SafeCounter struct {
  mu sync.Mutex
  value int
}

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

Sync package provides synchronization primitives: WaitGroup for waiting on goroutines, Mutex for mutual exclusion, and more.

Context Package

// Context with timeout
func worker(ctx context.Context) {
  select {
  case <-time.After(2 * time.Second):
    fmt.Println("Work done")
  case <-ctx.Done():
    fmt.Println("Cancelled:", ctx.Err())
  }
}

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
  defer cancel()
  
  go worker(ctx)
  
  select {
  case <-ctx.Done():
    fmt.Println("Main: timeout reached")
  }
}

// Context with value
ctx := context.WithValue(context.Background(), "key", "value")
if v := ctx.Value("key"); v != nil {
  fmt.Println("Value:", v)
}

Context carries deadlines, cancellation signals, and request-scoped values across API boundaries and between goroutines.

Patterns: Worker Pools

// Worker pool pattern
func worker(id int, jobs <-chan int, results chan<- int) {
  for j := range jobs {
    fmt.Printf("Worker %d processing job %d\n", id, j)
    time.Sleep(time.Second)
    results <- j * 2
  }
}

func main() {
  jobs := make(chan int, 100)
  results := make(chan int, 100)
  
  // Start 3 workers
  for w := 1; w <= 3; w++ {
    go worker(w, jobs, results)
  }
  
  // Send 9 jobs
  for j := 1; j <= 9; j++ {
    jobs <- j
  }
  close(jobs)
  
  // Collect results
  for a := 1; a <= 9; a++ {
    <-results
  }
}

Worker pools use multiple goroutines to process work from a queue. Useful for controlling concurrency and resource usage.

Collections

Arrays

// Array declaration
var a [3]int // Zero-valued array
b := [3]int{1, 2, 3} // Literal
c := [...]int{1, 2, 3, 4} // Compiler counts size
d := [2][3]int{{1, 2, 3}, {{4, 5, 6} // 2D array

// Access and modify
a[0] = 10
value := b[1] // 2

// Length
length := len(c) // 4

// Iteration
for i := 0; i < len(a); i++ {
  fmt.Println(a[i])
}

for i, v := range b {
  fmt.Printf("Index %d: Value %d\n", i, v)
}

// Arrays are values (copied when assigned)
arr1 := [2]int{1, 2}
arr2 := arr1 // Copy
arr2[0] = 10 // Doesn't affect arr1

Arrays are fixed-size sequences. Size is part of the type. Arrays are values, not references.

Slices

// Slice creation
var s1 []int // nil slice
s2 := []int{1, 2, 3} // Literal
s3 := make([]string, 3) // Length 3, capacity 3
s4 := make([]int, 2, 5) // Length 2, capacity 5

// From array
arr := [5]int{1, 2, 3, 4, 5}
s5 := arr[1:4] // [2, 3, 4]

// Slice operations
s2 = append(s2, 4) // [1, 2, 3, 4]
s2 = append(s2, 5, 6) // [1, 2, 3, 4, 5, 6]
s2 = append(s2, s3...) // Append another slice

// Copy slices
src := []int{1, 2, 3}
dst := make([]int, 2)
n := copy(dst, src) // n = 2, dst = [1, 2]

// Slice tricks
s2 = s2[1:] // Remove first element
s2 = s2[:len(s2)-1] // Remove last element
s2 = append(s2[:2], s2[3:]...) // Remove element at index 2

Slices are dynamic arrays with length and capacity. They reference underlying arrays. Use make() to create with specific capacity.

Maps

// Map creation
var m1 map[string]int // nil map
m2 := make(map[string]int) // Empty map
m3 := map[string]int{
  "apple": 5,
  "banana": 10,
}

// Operations
m2["key"] = 1 // Insert or update
value := m2["key"] // Retrieve
delete(m2, "key") // Delete

// Check if key exists
v, ok := m2["key"]
if ok {
  fmt.Println("Value:", v)
} else {
  fmt.Println("Key not found")
}

// Iteration
for k, v := range m3 {
  fmt.Println(k, v)
}

// Length
length := len(m3)

Maps are unordered key-value collections. Keys must be comparable (no slices, maps, or functions).

Sorting

// Sorting slices
ints := []int{4, 2, 8, 1}
sort.Ints(ints) // [1, 2, 4, 8]

strings := []string{"banana", "apple", "cherry"}
sort.Strings(strings) // ["apple", "banana", "cherry"]

// Custom sorting with sort.Interface
type Person struct {
  Name string
  Age int
}

type ByAge []Person

func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }

people := []Person{
  {"Alice", 30},
  {"Bob", 25},
  {"Charlie", 35},
}
sort.Sort(ByAge(people))

// sort.Slice (Go 1.8+)
sort.Slice(people, func(i, j int) bool {
  return people[i].Name < people[j].Name
})

Sort package provides sorting for built-in types. Implement sort.Interface or use sort.Slice for custom sorting.

Container Package

// List (doubly linked list)
list := list.New()
list.PushBack(1)
list.PushFront(2)
for e := list.Front(); e != nil; e = e.Next() {
  fmt.Println(e.Value)
}

// Ring (circular list)
r := ring.New(3)
for i := 0; i < 3; i++ {
  r.Value = i
  r = r.Next()
}
r.Do(func(x interface{}) {
  fmt.Println(x)
})

// Heap (priority queue)
type IntHeap []int

func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
  *h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
  old := *h
  n := len(old)
  x := old[n-1]
  *h = old[0 : n-1]
  return x
}

Container package provides list (doubly linked list), ring (circular list), and heap (priority queue) implementations.

Set Implementation

// Set using map[T]bool
type Set map[string]struct{}

func NewSet() Set {
  return make(Set)
}

func (s Set) Add(value string) {
  s[value] = struct{}{}
}

func (s Set) Remove(value string) {
  delete(s, value)
}

func (s Set) Contains(value string) bool {
  _, exists := s[value]
  return exists
}

// Using the set
s := NewSet()
s.Add("apple")
s.Add("banana")

if s.Contains("apple") {
  fmt.Println("Set contains apple")
}

// Generic set (Go 1.18+)
type Set[T comparable] map[T]struct{}

Go doesn't have built-in sets. Implement using maps with empty struct values (zero memory) as the most efficient approach.

Standard Library

fmt Package

// Printing
fmt.Print("Hello") // No newline
fmt.Println("Hello") // With newline
fmt.Printf("Name: %s, Age: %d", name, age)

// String formatting
s := fmt.Sprintf("Value: %v", data)
fmt.Fprintf(os.Stdout, "Writing: %s\n", text)

// Common format verbs
fmt.Printf("%v", value) // Default format
fmt.Printf("%+v", value) // Add field names (structs)
fmt.Printf("%#v", value) // Go syntax
fmt.Printf("%T", value) // Type
fmt.Printf("%.2f", 3.14159) // Float precision

// Scanning input
var input string
fmt.Scan(&input)
fmt.Scanf("%s %d", &name, &age)
fmt.Scanln(&input)

fmt package provides formatted I/O. Use Print for output, Scan for input, Sprintf for string formatting.

os & io Packages

// File operations
file, err := os.Open("file.txt")
defer file.Close()

data := []byte("Hello")
err = os.WriteFile("output.txt", data, 0644)

content, err := os.ReadFile("file.txt")

// Environment variables
path := os.Getenv("PATH")
os.Setenv("KEY", "value")

// Command-line arguments
args := os.Args
if len(args) > 1 {
  fmt.Println("First arg:", args[1])
}

// io utilities
n, err := io.Copy(dst, src)
all, err := io.ReadAll(reader)
io.WriteString(writer, "text")

os provides OS interface (files, env vars, args). io provides basic I/O interfaces and utilities.

net/http Package

// HTTP server
func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}

http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)

// HTTP client
resp, err := http.Get("https://api.example.com")
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)

// POST request
jsonData := []byte(`{"name":"John"}`)
resp, err := http.Post("https://api.example.com",
  "application/json", bytes.NewBuffer(jsonData))

// Custom client with timeout
client := &http.Client{
  Timeout: 10 * time.Second,
}
req, _ := http.NewRequest("GET", "https://example.com", nil)
resp, err := client.Do(req)

net/http provides HTTP client and server implementations. Built-in routing, headers, cookies, and file serving.

encoding/json

// Marshaling (struct to JSON)
type Person struct {
  Name string `json:"name"`
  Age int `json:"age"`
}

p := Person{Name: "Alice", Age: 30}
jsonData, err := json.Marshal(p)
// {"name":"Alice","age":30}

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

// Unmarshaling (JSON to struct)
var p2 Person
err := json.Unmarshal(jsonData, &p2)

// Streaming encoder/decoder
enc := json.NewEncoder(os.Stdout)
enc.Encode(p)

dec := json.NewDecoder(os.Stdin)
var data map[string]interface{}{}
dec.Decode(&data)

encoding/json provides JSON marshaling and unmarshaling. Use struct tags to customize field names and behavior.

time Package

// Current time
now := time.Now()
fmt.Println(now.Year(), now.Month(), now.Day())

// Creating time
t := time.Date(2023, time.January, 10, 23, 0, 0, 0, time.UTC)

// Parsing time
t, err := time.Parse("2006-01-02", "2023-01-10")
t, err := time.Parse(time.RFC3339, "2023-01-10T15:30:00Z")

// Formatting time
formatted := now.Format("2006-01-02 15:04:05")
formatted := now.Format(time.RFC1123)

// Duration
duration := 2 * time.Hour + 30 * time.Minute
later := now.Add(duration)
earlier := now.Add(-duration)

// Timer and Ticker
timer := time.NewTimer(2 * time.Second)
<-timer.C

ticker := time.NewTicker(1 * time.Second)
for t := range ticker.C {
  fmt.Println("Tick at", t)
}

time package provides time measurement and display. Note: Use "2006-01-02 15:04:05" as reference time for formatting.

Other Useful Packages

// strconv - string conversions
s := strconv.Itoa(123) // "123"
i, err := strconv.Atoi("456") // 456
b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.14", 64)

// strings - string manipulation
contains := strings.Contains("hello", "ell")
count := strings.Count("cheese", "e")
fields := strings.Fields("a b c") // ["a", "b", "c"]
lower := strings.ToLower("HELLO")
replaced := strings.Replace("foo", "o", "a", -1)

// regexp - regular expressions
matched, err := regexp.MatchString("^[a-z]+$", "hello")
re := regexp.MustCompile(`^\d+$`)
matches := re.FindString("123 abc") // "123"

// path/filepath - file paths
dir := filepath.Dir("/home/user/file.txt")
base := filepath.Base("/home/user/file.txt")
ext := filepath.Ext("file.txt")
abs, err := filepath.Abs("file.txt")

Go's standard library is extensive. Key packages include strconv, strings, regexp, path/filepath, and many more for common tasks.

Go Best Practices Summary

• Use gofmt to format code automatically

• Handle errors explicitly (don't ignore them)

• Prefer composition over inheritance

• Return errors, don't panic (except for unrecoverable errors)

• Use interfaces for abstraction and testing

• Keep packages small and focused on single responsibility

• Write tests (use testing package)

• Use go vet and staticcheck for code analysis

• Document exported functions and types with comments

Go (Golang) Cheatsheet © 2023 | Complete reference for Go developers

Remember: go fmt your code and go test often!

Go version referenced: 1.21 | Standard library coverage: Comprehensive