Go Standard Library
Go has a rich standard library. Here are the packages you'll use most often.
fmt - Formatted I/O
import "fmt"
// Print functions
fmt.Print("Hello") // No newline
fmt.Println("Hello") // With newline
fmt.Printf("Name: %s\n", n) // Formatted
// Sprint functions (return string)
s := fmt.Sprint("Hello")
s := fmt.Sprintf("Name: %s", name)
// Fprint functions (write to io.Writer)
fmt.Fprint(os.Stderr, "Error!")
fmt.Fprintf(w, "Status: %d", code)
// Scanning
var name string
var age int
fmt.Scan(&name) // Read word
fmt.Scanf("%s %d", &name, &age) // Formatted
fmt.Scanln(&name) // Read line
strings - String Manipulation
import "strings"
s := "Hello, World!"
strings.Contains(s, "World") // true
strings.HasPrefix(s, "Hello") // true
strings.HasSuffix(s, "!") // true
strings.Index(s, "o") // 4
strings.LastIndex(s, "o") // 8
strings.Count(s, "l") // 3
strings.ToUpper(s) // "HELLO, WORLD!"
strings.ToLower(s) // "hello, world!"
strings.Title(s) // "Hello, World!" (deprecated, use cases.Title)
strings.TrimSpace(" hi ") // "hi"
strings.Trim("!!hi!!", "!") // "hi"
strings.TrimPrefix("hello", "he") // "llo"
strings.TrimSuffix("hello", "lo") // "hel"
strings.Replace(s, "World", "Go", 1) // "Hello, Go!"
strings.ReplaceAll(s, "l", "L") // "HeLLo, WorLd!"
strings.Split("a,b,c", ",") // []string{"a", "b", "c"}
strings.Join([]string{"a","b"}, "-") // "a-b"
strings.Repeat("ab", 3) // "ababab"
// Builder for efficient concatenation
var b strings.Builder
b.WriteString("Hello")
b.WriteString(", ")
b.WriteString("World!")
result := b.String() // "Hello, World!"
strconv - String Conversions
import "strconv"
// String to number
i, err := strconv.Atoi("42") // int
i64, err := strconv.ParseInt("42", 10, 64) // int64
f, err := strconv.ParseFloat("3.14", 64) // float64
b, err := strconv.ParseBool("true") // bool
// Number to string
s := strconv.Itoa(42) // "42"
s := strconv.FormatInt(42, 10) // "42"
s := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
s := strconv.FormatBool(true) // "true"
// Quote/Unquote
s := strconv.Quote("hello\nworld") // "\"hello\\nworld\""
s, _ := strconv.Unquote("\"hello\"") // "hello"
io - Basic I/O
import "io"
// Core interfaces
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Common functions
n, err := io.Copy(dst, src) // Copy all data
n, err := io.CopyN(dst, src, 1024) // Copy n bytes
data, err := io.ReadAll(r) // Read everything
// Utilities
r := io.LimitReader(src, 1024) // Limit reading
r := io.TeeReader(src, dst) // Read and copy
w := io.MultiWriter(w1, w2) // Write to multiple
r := io.MultiReader(r1, r2) // Read from multiple
// Discard
io.Copy(io.Discard, r) // Read and discard
os - Operating System
import "os"
// Environment
os.Getenv("HOME")
os.Setenv("KEY", "value")
os.Environ() // []string{"KEY=value", ...}
// Files
f, err := os.Open("file.txt") // Read-only
f, err := os.Create("file.txt") // Create/truncate
f, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE, 0644)
data, err := os.ReadFile("file.txt") // Read entire file
err := os.WriteFile("file.txt", data, 0644) // Write entire file
// File operations
err := os.Remove("file.txt")
err := os.RemoveAll("dir")
err := os.Rename("old.txt", "new.txt")
err := os.Mkdir("dir", 0755)
err := os.MkdirAll("path/to/dir", 0755)
info, err := os.Stat("file.txt")
info.Name() // filename
info.Size() // size in bytes
info.IsDir() // is directory?
info.ModTime() // modification time
// Working directory
cwd, err := os.Getwd()
err := os.Chdir("/path")
// Process
os.Exit(1) // Exit with code
os.Args // Command-line arguments
os.Stdin, os.Stdout, os.Stderr // Standard streams
path/filepath - File Paths
import "path/filepath"
// Path manipulation (OS-aware)
filepath.Join("dir", "file.txt") // "dir/file.txt" or "dir\file.txt"
filepath.Dir("/path/to/file.txt") // "/path/to"
filepath.Base("/path/to/file.txt") // "file.txt"
filepath.Ext("file.txt") // ".txt"
filepath.Abs("relative/path") // Absolute path
filepath.Rel("/base", "/base/path") // "path"
filepath.Clean("path/../other") // "other"
// Walking directories
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Println(path)
return nil
})
// WalkDir (Go 1.16+, more efficient)
filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
fmt.Println(path)
return nil
})
// Globbing
matches, err := filepath.Glob("*.go")
time - Time and Duration
import "time"
// Current time
now := time.Now()
now.Year(), now.Month(), now.Day()
now.Hour(), now.Minute(), now.Second()
now.Weekday() // time.Sunday, etc.
now.Unix() // Unix timestamp
// Creating times
t := time.Date(2024, time.January, 1, 12, 0, 0, 0, time.UTC)
// Parsing
t, err := time.Parse("2006-01-02", "2024-01-15")
t, err := time.Parse(time.RFC3339, "2024-01-15T12:00:00Z")
// Formatting (use reference time: Mon Jan 2 15:04:05 MST 2006)
t.Format("2006-01-02") // "2024-01-15"
t.Format("Jan 2, 2006") // "Jan 15, 2024"
t.Format(time.RFC3339) // "2024-01-15T12:00:00Z"
t.Format("3:04 PM") // "12:00 PM"
// Duration
d := 5 * time.Second
d := time.Hour + 30*time.Minute
d := time.Duration(n) * time.Millisecond
// Arithmetic
later := now.Add(24 * time.Hour)
earlier := now.Add(-1 * time.Hour)
diff := t2.Sub(t1) // Duration
// Comparison
t1.Before(t2)
t1.After(t2)
t1.Equal(t2)
// Sleeping and timers
time.Sleep(time.Second)
timer := time.NewTimer(time.Second)
<-timer.C // Blocks until timer fires
timer.Stop()
ticker := time.NewTicker(time.Second)
for t := range ticker.C {
fmt.Println("Tick at", t)
}
ticker.Stop()
// Timeout
select {
case result := <-ch:
// Got result
case <-time.After(5 * time.Second):
// Timeout
}
encoding/json - JSON
import "encoding/json"
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Age int `json:"age"`
}
// Marshal (struct to JSON)
user := User{Name: "Alice", Age: 30}
data, err := json.Marshal(user)
// {"name":"Alice","age":30}
// Pretty print
data, err := json.MarshalIndent(user, "", " ")
// Unmarshal (JSON to struct)
var user User
err := json.Unmarshal(data, &user)
// Streaming (for large data)
// Encoder
encoder := json.NewEncoder(w)
encoder.Encode(user)
// Decoder
decoder := json.NewDecoder(r)
decoder.Decode(&user)
// Working with unknown JSON
var result map[string]interface{}
json.Unmarshal(data, &result)
// Or with any
var result any
json.Unmarshal(data, &result)
net/http - HTTP Client & Server
HTTP Client
import "net/http"
// Simple GET
resp, err := http.Get("https://api.example.com/data")
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
// Simple POST
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
// Custom request
req, err := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer token")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
// With context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := http.DefaultClient.Do(req)
HTTP Server
import "net/http"
// Simple handler
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
}
// JSON handler
func jsonHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "hello"})
}
// Register handlers
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/data", jsonHandler)
// Start server
http.ListenAndServe(":8080", nil)
// With custom mux
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/api/", apiHandler)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
server.ListenAndServe()
log - Logging
import "log"
// Basic logging
log.Print("Info message")
log.Printf("User: %s", name)
log.Println("With newline")
// Fatal (logs and exits)
log.Fatal("Critical error")
log.Fatalf("Error: %v", err)
// Panic (logs and panics)
log.Panic("Unrecoverable error")
// Custom logger
logger := log.New(os.Stdout, "APP: ", log.Ldate|log.Ltime|log.Lshortfile)
logger.Println("Custom log")
// Flags
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
// log.Ldate // 2009/01/23
// log.Ltime // 01:23:23
// log.Lmicroseconds
// log.Llongfile // /a/b/c/d.go:23
// log.Lshortfile // d.go:23
// log.LUTC // Use UTC
// log.Lmsgprefix // Move prefix to before message
// Log to file
f, _ := os.OpenFile("app.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
log.SetOutput(f)
log/slog - Structured Logging (Go 1.21+)
import "log/slog"
// Basic usage
slog.Info("User logged in", "user_id", 123, "ip", "192.168.1.1")
slog.Warn("Rate limit approaching", "current", 95, "max", 100)
slog.Error("Failed to save", "error", err)
// With context
slog.InfoContext(ctx, "Processing request")
// Create custom logger
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("Structured log", "key", "value")
// With attributes
logger := slog.With("service", "api", "version", "1.0")
logger.Info("Request received")
// Log levels
slog.Debug("debug message") // Only shown if level allows
slog.Info("info message")
slog.Warn("warning message")
slog.Error("error message")
regexp - Regular Expressions
import "regexp"
// Compile (panics on error)
re := regexp.MustCompile(`\d+`)
// Compile (returns error)
re, err := regexp.Compile(`\d+`)
// Matching
re.MatchString("abc123") // true
re.FindString("abc123def") // "123"
re.FindAllString("a1b2c3", -1) // []string{"1", "2", "3"}
// With submatches
re := regexp.MustCompile(`(\w+)@(\w+)\.(\w+)`)
matches := re.FindStringSubmatch("user@example.com")
// []string{"user@example.com", "user", "example", "com"}
// Named groups
re := regexp.MustCompile(`(?P<user>\w+)@(?P<domain>\w+\.\w+)`)
matches := re.FindStringSubmatch("user@example.com")
names := re.SubexpNames() // []string{"", "user", "domain"}
// Replace
re := regexp.MustCompile(`\s+`)
re.ReplaceAllString("a b c", " ") // "a b c"
// Split
re := regexp.MustCompile(`[,;]`)
re.Split("a,b;c", -1) // []string{"a", "b", "c"}
sort - Sorting
import "sort"
// Sort slices
nums := []int{3, 1, 4, 1, 5}
sort.Ints(nums) // [1, 1, 3, 4, 5]
strs := []string{"banana", "apple", "cherry"}
sort.Strings(strs) // [apple, banana, cherry]
// Reverse
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
// Custom sorting
sort.Slice(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
// Stable sort
sort.SliceStable(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
// Check if sorted
sort.IntsAreSorted(nums)
// Binary search
i := sort.SearchInts(nums, 4) // Index where 4 should be
sync - Synchronization
import "sync"
// WaitGroup
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// work
}()
wg.Wait()
// Mutex
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()
// RWMutex
var mu sync.RWMutex
mu.RLock() // Multiple readers OK
mu.RUnlock()
mu.Lock() // Exclusive write
mu.Unlock()
// Once
var once sync.Once
once.Do(func() {
// Runs exactly once
})
// Map (concurrent-safe)
var m sync.Map
m.Store("key", "value")
value, ok := m.Load("key")
m.Delete("key")
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true // Continue iteration
})
// Pool
var pool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
buf := pool.Get().(*bytes.Buffer)
defer pool.Put(buf)
context - Request Scoping
import "context"
// Background context (top-level)
ctx := context.Background()
// TODO context (when unsure)
ctx := context.TODO()
// With cancellation
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// With deadline
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Hour))
defer cancel()
// With value (use sparingly)
ctx := context.WithValue(parentCtx, "userID", 123)
userID := ctx.Value("userID").(int)
// Check for cancellation
select {
case <-ctx.Done():
return ctx.Err() // context.Canceled or context.DeadlineExceeded
default:
// Continue
}
Next Steps
Continue to 13-best-practices.md to learn about Go idioms and best practices.