Table of Contents
- 1.
fmt: Formatting and I/O - 2.
os: Operating System Interactions - 3.
ioandbufio: Input/Output Operations - 4.
strconv: String Conversion - 5.
mathandmath/rand: Mathematics and Random Numbers - 6.
encoding/json: JSON Serialization/Deserialization - 7.
net/http: HTTP Servers and Clients - 8.
sync: Synchronization Primitives - 9.
errors: Error Handling - 10.
time: Time and Duration Management - Best Practices for Using Built-in Packages
- Conclusion
- References
1. fmt: Formatting and I/O
The fmt package is the workhorse for formatted input and output in Go. It provides functions to print to the console, format strings, and read user input, making it indispensable for debugging, logging, and user interaction.
Key Features
- Output Functions:
Print,Println,Printf(formatted output toos.Stdout). - String Formatting:
Sprintf(returns a formatted string),Fprintf(formatted output to aio.Writer). - Input Functions:
Scan,Scanln,Scanf(read fromos.Stdin). - Format Verbs: Special placeholders (e.g.,
%dfor integers,%sfor strings) to control formatting.
Example: Formatting and Printing
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// Basic printing
fmt.Println("Hello, Go!") // Hello, Go!
// Formatted string with Printf
name := "Alice"
age := 30
fmt.Printf("Name: %s, Age: %d\n", name, age) // Name: Alice, Age: 30
// Formatting a struct with %+v (shows field names)
p := Person{Name: "Bob", Age: 25}
fmt.Printf("Person: %+v\n", p) // Person: {Name:Bob Age:25}
// Scanning input
var userInput string
fmt.Print("Enter something: ")
fmt.Scanln(&userInput)
fmt.Printf("You entered: %s\n", userInput)
}
Common Format Verbs
| Verb | Description | Example |
|---|---|---|
%d | Base-10 integer | %d → 42 |
%s | String | %s → "hello" |
%v | Default format (any type) | %v → {Alice 30} |
%+v | Verbose format (structs) | %+v → {Name:Alice Age:30} |
%t | Boolean | %t → true |
2. os: Operating System Interactions
The os package provides cross-platform utilities for interacting with the operating system, including file manipulation, environment variables, command-line arguments, and process control.
Key Features
- File Operations:
Create,Open,ReadFile,WriteFile(simplified file I/O). - Environment Variables:
Getenv,Setenv,Environ(access/modify env vars). - Command-Line Args:
os.Args(slice of arguments passed to the program). - Process Control:
Exit,Getpid(terminate the program, get process ID).
Example: File I/O and Environment Variables
package main
import (
"fmt"
"os"
)
func main() {
// Read command-line arguments (os.Args[0] is the program name)
if len(os.Args) > 1 {
fmt.Println("Arguments:", os.Args[1:]) // e.g., [arg1 arg2]
}
// Read environment variable
goPath := os.Getenv("GOPATH")
fmt.Println("GOPATH:", goPath)
// Write to a file (simplified with WriteFile)
data := []byte("Hello, File!\n")
err := os.WriteFile("example.txt", data, 0644) // 0644 = read/write for owner, read for others
if err != nil {
panic(err)
}
// Read from a file
content, err := os.ReadFile("example.txt")
if err != nil {
panic(err)
}
fmt.Println("File content:", string(content)) // File content: Hello, File!
}
Best Practice: Always Check Errors
Most os functions return an error (e.g., os.Open returns (*os.File, error)). Always handle errors explicitly to avoid silent failures.
3. io and bufio: Input/Output Operations
Go’s IO model is built around two core interfaces from the io package: io.Reader and io.Writer. These interfaces abstract input and output, enabling flexible and composable IO operations. The bufio package adds buffered IO for efficiency.
Key Concepts
io.Reader: Defines aRead(p []byte) (n int, err error)method to read data into a byte slice.io.Writer: Defines aWrite(p []byte) (n int, err error)method to write data from a byte slice.bufio: Buffers IO operations to reduce system calls (e.g., reading/writing in chunks).
Example: Using io.Reader/io.Writer and bufio
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
// io.Reader example: Read from a string (strings.NewReader implements io.Reader)
reader := strings.NewReader("Hello, io.Reader!")
buf := make([]byte, 8) // Read 8 bytes at a time
for {
n, err := reader.Read(buf)
if err == io.EOF { // End of input
break
}
if err != nil {
panic(err)
}
fmt.Printf("Read %d bytes: %s\n", n, buf[:n])
}
// bufio.Scanner: Efficiently read lines from a reader (e.g., stdin)
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Enter lines (Ctrl+D to exit):")
for scanner.Scan() {
line := scanner.Text()
fmt.Printf("You typed: %s\n", line)
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "Error reading: %v\n", err)
}
// io.Copy: Copy data from a reader to a writer (e.g., file to stdout)
file, err := os.Open("example.txt")
if err != nil {
panic(err)
}
defer file.Close() // Ensure the file is closed when done
fmt.Println("Copying file to stdout:")
_, err = io.Copy(os.Stdout, file) // os.Stdout implements io.Writer
if err != nil {
panic(err)
}
}
4. strconv: String Conversion
The strconv package converts between strings and basic data types (e.g., integers, floats, booleans). It is critical for parsing user input, configuration files, or API responses.
Key Functions
- String ↔ Int:
Atoi(string → int),Itoa(int → string),ParseInt,FormatInt. - String ↔ Float:
ParseFloat,FormatFloat. - String ↔ Bool:
ParseBool,FormatBool.
Example: String Conversion
package main
import (
"fmt"
"strconv"
)
func main() {
// String to int (Atoi = "ASCII to integer")
numStr := "42"
num, err := strconv.Atoi(numStr)
if err != nil {
panic(err)
}
fmt.Println(num + 8) // 50
// Int to string (Itoa = "integer to ASCII")
num2 := 100
num2Str := strconv.Itoa(num2)
fmt.Println("Number as string:", num2Str) // Number as string: 100
// String to float
floatStr := "3.1415"
pi, err := strconv.ParseFloat(floatStr, 64) // 64 = bit size
if err != nil {
panic(err)
}
fmt.Println(pi * 2) // 6.283
// Format int as binary string
binaryStr := strconv.FormatInt(42, 2) // Base 2
fmt.Println("42 in binary:", binaryStr) // 42 in binary: 101010
}
5. math and math/rand: Mathematics and Random Numbers
The math package provides basic mathematical functions and constants, while math/rand handles random number generation.
Key Features
math: Constants likemath.Pi(3.1415…) andmath.E(2.718…), plus functions likeSqrt,Sin,Min,Max.math/rand: Pseudorandom number generators (PRNGs) for integers, floats, and permutations.
Example: Math and Random Numbers
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func main() {
// Math constants and functions
fmt.Println("Pi:", math.Pi) // Pi: 3.141592653589793
fmt.Println("Square root of 25:", math.Sqrt(25)) // 5
fmt.Println("Max of 3 and 7:", math.Max(3, 7)) // 7
// Random numbers: Seed the PRNG (use current time for unique sequences)
rand.Seed(time.Now().UnixNano()) // Required for non-deterministic output
// Generate random int in [0, 100)
randInt := rand.Intn(100)
fmt.Println("Random int (0-99):", randInt)
// Generate random float in [0.0, 1.0)
randFloat := rand.Float64()
fmt.Println("Random float (0.0-1.0):", randFloat)
// Generate a random permutation of 5 elements
perm := rand.Perm(5)
fmt.Println("Random permutation:", perm) // e.g., [3 1 4 0 2]
}
6. encoding/json: JSON Serialization/Deserialization
The encoding/json package simplifies working with JSON data by providing Marshal (struct → JSON) and Unmarshal (JSON → struct) functions. It uses struct tags to map Go fields to JSON keys.
Key Concepts
json.Marshal(v interface{}) ([]byte, error): Converts a Go value to a JSON byte slice.json.Unmarshal(data []byte, v interface{}) error: Converts JSON data into a Go value.- Struct Tags:
json:"field_name"to customize JSON keys (e.g.,Name string 'json:"user_name"').
Example: JSON Marshaling/Unmarshaling
package main
import (
"encoding/json"
"fmt"
)
// Define a struct with JSON tags
type User struct {
Name string `json:"name"` // JSON key: "name"
Age int `json:"age"` // JSON key: "age"
Email string `json:"email"` // JSON key: "email"
}
func main() {
// Marshal: Go struct → JSON
user := User{Name: "Alice", Age: 30, Email: "[email protected]"}
jsonData, err := json.Marshal(user)
if err != nil {
panic(err)
}
fmt.Println("Marshaled JSON:", string(jsonData))
// Output: {"name":"Alice","age":30,"email":"[email protected]"}
// Unmarshal: JSON → Go struct
jsonStr := `{"name":"Bob","age":25,"email":"[email protected]"}`
var user2 User
err = json.Unmarshal([]byte(jsonStr), &user2)
if err != nil {
panic(err)
}
fmt.Printf("Unmarshaled User: %+v\n", user2)
// Output: Unmarshaled User: {Name:Bob Age:25 Email:[email protected]}
// Handle unknown fields (use json:",ignoreUnknown" to skip)
badJSON := `{"name":"Charlie","age":35,"unknown_field":"oops"}`
var user3 User
err = json.Unmarshal([]byte(badJSON), &user3)
fmt.Println("Error with unknown field:", err) // Error: invalid field "unknown_field"
}
7. net/http: HTTP Servers and Clients
The net/http package makes building HTTP servers and clients trivial. It abstracts low-level details, allowing you to focus on application logic.
Key Features
- HTTP Servers:
http.HandleFunc(register handlers),http.ListenAndServe(start server). - HTTP Clients:
http.Get,http.Post(send requests),http.Response(process responses).
Example: Simple HTTP Server and Client
package main
import (
"encoding/json"
"fmt"
"net/http"
)
// User handler for /api/user endpoint
func userHandler(w http.ResponseWriter, r *http.Request) {
user := User{Name: "Alice", Age: 30}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user) // Write JSON directly to response writer
}
func main() {
// Define routes
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, HTTP!")
})
http.HandleFunc("/api/user", userHandler)
// Start server (runs in background)
go func() {
fmt.Println("Server starting on :8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}()
// Wait for server to start (simplified for example)
time.Sleep(1 * time.Second)
// HTTP Client: Send GET request to the server
resp, err := http.Get("http://localhost:8080/api/user")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// Decode JSON response
var user User
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
panic(err)
}
fmt.Println("Client received:", user) // Client received: {Alice 30 }
}
8. sync: Synchronization Primitives
Go’s concurrency model relies on goroutines, but shared state between goroutines requires synchronization. The sync package provides primitives like Mutex (mutual exclusion) and WaitGroup to manage concurrency safely.
Key Primitives
sync.Mutex: Ensures only one goroutine accesses shared data at a time (prevents race conditions).sync.WaitGroup: Waits for a collection of goroutines to finish.
Example: Using Mutex and WaitGroup
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex // Mutex to protect counter
wg sync.WaitGroup
)
func increment() {
defer wg.Done() // Notify WaitGroup when done
mu.Lock() // Acquire lock
counter++ // Critical section (shared state)
mu.Unlock() // Release lock
}
func main() {
// Launch 1000 goroutines to increment the counter
wg.Add(1000)
for i := 0; i < 1000; i++ {
go increment()
}
wg.Wait() // Wait for all goroutines to finish
fmt.Println("Final counter:", counter) // 1000 (no race conditions!)
}
9. errors: Error Handling
Go uses explicit error handling (no exceptions). The errors package provides New to create simple errors and Unwrap to work with wrapped errors (Go 1.13+).
Example: Creating and Wrapping Errors
package main
import (
"errors"
"fmt"
)
func validateAge(age int) error {
if age < 0 {
return errors.New("age cannot be negative")
}
if age > 150 {
return fmt.Errorf("invalid age: %d (too old)", age) // Formatted error
}
return nil
}
func main() {
err := validateAge(200)
if err != nil {
fmt.Println("Error:", err) // Error: invalid age: 200 (too old)
}
}
10. time: Time and Duration Management
The time package handles time parsing, formatting, and duration calculations. It is essential for scheduling, logging, and measuring performance.
Key Types/Functions
time.Time: Represents a specific point in time.time.Duration: Represents a time interval (e.g.,10*time.Second).time.Now(): Returns the current time.time.Parse(layout, value string) (Time, error): Parses a string into atime.Time.
Example: Time Operations
package main
import (
"fmt"
"time"
)
func main() {
// Current time
now := time.Now()
fmt.Println("Now:", now) // e.g., 2024-05-20 15:30:45.123456789 +0200 CEST
// Format time (layout uses reference time: Mon Jan 2 15:04:05 MST 2006)
formatted := now.Format("2006-01-02 15:04:05")
fmt.Println("Formatted:", formatted) // e.g., 2024-05-20 15:30:45
// Parse time string
parsedTime, err := time.Parse("2006-01-02", "2024-12-25")
if err != nil {
panic(err)
}
fmt.Println("Parsed time:", parsedTime) // 2024-12-25 00:00:00 +0000 UTC
// Duration: Add 2 hours to now
later := now.Add(2 * time.Hour)
fmt.Println("In 2 hours:", later.Format("15:04"))
// Measure execution time
start := time.Now()
time.Sleep(1 * time.Second) // Simulate work
elapsed := time.Since(start)
fmt.Println("Elapsed time:", elapsed) // ~1s
}
Best Practices for Using Built-in Packages
- Leverage Interfaces: Use
io.Reader/io.Writerfor flexible IO operations. - Handle Errors: Always check errors returned by package functions.
- Close Resources: Use
deferto close files, network connections, etc. - Read the Docs: The Go standard library docs are comprehensive—refer to them for edge cases.
Conclusion
Go’s built-in packages are a treasure trove of functionality that accelerates development and ensures reliability. By mastering packages like fmt, os, encoding/json, and net/http, you can build powerful applications with minimal external dependencies. Explore the standard library further to unlock Go’s full potential!