General Tools
API Client (Postman) DB Admin (Adminer) QR Generator JSON Formatter JWT Decoder Regex Tester Cron Generator UUID Generator Hash Generator
India Utilities
UPI QR Generator EMI Calculator GST Calculator Photo Resizer PDF Compressor
Frontend Tools
Palette Generator Gradient Generator Shadow Generator SQL Formatter
Productivity
Temporary Notes One-Time Secret Clipboard Sync Timezone Converter
PDF & Files
PDF Merge Tool Image Compressor HEIC to JPG Image to Text (OCR) PDF Password Signature Bg Remover

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