Learning Go, 2nd Edition

Book description

Go has rapidly become the preferred language for building web services. Plenty of tutorials are available to teach Go's syntax to developers with experience in other programming languages, but tutorials aren't enough. They don't teach Go's idioms, so developers end up recreating patterns that don't make sense in a Go context. This practical guide provides the essential background you need to write clear and idiomatic Go.

No matter your level of experience, you'll learn how to think like a Go developer. Author Jon Bodner introduces the design patterns experienced Go developers have adopted and explores the rationale for using them. This updated edition also shows you how Go's generics support fits into the language.

This book helps you:

  • Write idiomatic code in Go and design a Go project
  • Understand the reasons behind Go's design decisions
  • Set up a Go development environment for a solo developer or team
  • Learn how and when to use reflection, unsafe, and cgo
  • Discover how Go's features allow the language to run efficiently
  • Know which Go features you should use sparingly or not at all
  • Use Go's tools to improve performance, optimize memory usage, and reduce garbage collection
  • Learn how to use Go's advanced development tools

Table of contents

  1. Preface
    1. Who Should Read This Book
    2. Conventions Used in This Book
    3. Using Code Examples
    4. O’Reilly Online Learning
    5. How to Contact Us
    6. Acknowledgments for the 2nd Edition
    7. Acknowledgments for the 1st Edition
  2. 1. Setting Up Your Go Environment
    1. Installing the Go Tools
      1. Troubleshooting Your Go Installation
      2. Go Tooling
    2. Your First Go Program
      1. Making a Go Module
      2. go build
      3. go fmt
      4. go vet
    3. Choose Your Tools
      1. Visual Studio Code
      2. GoLand
      3. The Go Playground
    4. Makefiles
    5. The Go Compatibility Promise
    6. Staying Up-to-Date
    7. Exercises
    8. Wrapping Up
  3. 2. Predeclared Types and Declarations
    1. The Predeclared Types
      1. The Zero Value
      2. Literals
      3. Booleans
      4. Numeric Types
      5. A Taste of Strings and Runes
      6. Explicit Type Conversion
      7. Literals Are Untyped
    2. var Versus :=
    3. Using const
    4. Typed and Untyped Constants
    5. Unused Variables
    6. Naming Variables and Constants
    7. Exercises
    8. Wrapping Up
  4. 3. Composite Types
    1. Arrays—Too Rigid to Use Directly
    2. Slices
      1. len
      2. append
      3. Capacity
      4. make
      5. Emptying a Slice
      6. Declaring Your Slice
      7. Slicing Slices
      8. copy
      9. Converting Arrays to Slices
      10. Converting Slices to Arrays
    3. Strings and Runes and Bytes
    4. Maps
      1. Reading and Writing a Map
      2. The comma ok Idiom
      3. Deleting from Maps
      4. Emptying a Map
      5. Comparing Maps
      6. Using Maps as Sets
    5. Structs
      1. Anonymous Structs
      2. Comparing and Converting Structs
    6. Exercises
    7. Wrapping Up
  5. 4. Blocks, Shadows, and Control Structures
    1. Blocks
    2. Shadowing Variables
    3. if   
    4. for, Four Ways
      1. The Complete for Statement
      2. The Condition-Only for Statement
      3. The Infinite for Statement
      4. break and continue
      5. The for-range Statement
      6. Labeling Your for Statements
      7. Choosing the Right for Statement
    5. switch
      1. Blank Switches
      2. Choosing Between if and switch
    6. goto—Yes, goto
    7. Exercises
    8. Wrapping Up
  6. 5. Functions
    1. Declaring and Calling Functions
      1. Simulating Named and Optional Parameters
      2. Variadic Input Parameters and Slices
      3. Multiple Return Values
      4. Multiple Return Values Are Multiple Values
      5. Ignoring Returned Values
      6. Named Return Values
      7. Blank Returns—Never Use These!
    2. Functions Are Values
      1. Function Type Declarations
      2. Anonymous Functions
    3. Closures
      1. Passing Functions as Parameters
      2. Returning Functions from Functions
    4. defer
    5. Go Is Call by Value
    6. Exercises
    7. Wrapping Up
  7. 6. Pointers
    1. A Quick Pointer Primer
    2. Don’t Fear the Pointers
    3. Pointers Indicate Mutable Parameters
    4. Pointers Are a Last Resort
    5. Pointer Passing Performance
    6. The Zero Value Versus No Value
    7. The Difference Between Maps and Slices
    8. Slices as Buffers
    9. Reducing the Garbage Collector’s Workload
    10. Tuning the Garbage Collector
    11. Exercises
    12. Wrapping Up
  8. 7. Types, Methods, and Interfaces
    1. Types in Go
    2. Methods
      1. Pointer Receivers and Value Receivers
      2. Code Your Methods for nil Instances
      3. Methods Are Functions Too
      4. Functions Versus Methods
      5. Type Declarations Aren’t Inheritance
      6. Types Are Executable Documentation
    3. iota Is for Enumerations—Sometimes
    4. Use Embedding for Composition
    5. Embedding Is Not Inheritance
    6. A Quick Lesson on Interfaces
    7. Interfaces Are Type-Safe Duck Typing
    8. Embedding and Interfaces
    9. Accept Interfaces, Return Structs
    10. Interfaces and nil
    11. Interfaces Are Comparable
    12. The Empty Interface Says Nothing
    13. Type Assertions and Type Switches
    14. Use Type Assertions and Type Switches Sparingly
    15. Function Types Are a Bridge to Interfaces
    16. Implicit Interfaces Make Dependency Injection Easier
    17. Wire
    18. Go Isn’t Particularly Object-Oriented (and That’s Great)
    19. Exercises
    20. Wrapping Up
  9. 8. Generics
    1. Generics Reduce Repetitive Code and Increase Type Safety
    2. Introducing Generics in Go
    3. Generic Functions Abstract Algorithms
    4. Generics and Interfaces
    5. Use Type Terms to Specify Operators
    6. Type Inference and Generics
    7. Type Elements Limit Constants
    8. Combining Generic Functions with Generic Data Structures
    9. More on comparable
    10. Things That Are Left Out
    11. Idiomatic Go and Generics
    12. Adding Generics to the Standard Library
    13. Future Features Unlocked
    14. Exercises
    15. Wrapping Up
  10. 9. Errors
    1. How to Handle Errors: The Basics
    2. Use Strings for Simple Errors
    3. Sentinel Errors
    4. Errors Are Values
    5. Wrapping Errors
    6. Wrapping Multiple Errors
    7. Is and As
    8. Wrapping Errors with defer
    9. panic and recover
    10. Getting a Stack Trace from an Error
    11. Exercises
    12. Wrapping Up
  11. 10. Modules, Packages, and Imports
    1. Repositories, Modules, and Packages
    2. Using go.mod
      1. Use the go Directive to Manage Go Build Versions
      2. The require Directive
    3. Building Packages
      1. Importing and Exporting
      2. Creating and Accessing a Package
      3. Naming Packages
      4. Overriding a Package’s Name
      5. Documenting Your Code with Go Doc Comments
      6. Using the internal Package
      7. Avoiding Circular Dependencies
      8. Organizing Your Module
      9. Gracefully Renaming and Reorganizing Your API
      10. Avoiding the init Function if Possible
    4. Working with Modules
      1. Importing Third-Party Code
      2. Working with Versions
      3. Minimal Version Selection
      4. Updating to Compatible Versions
      5. Updating to Incompatible Versions
      6. Vendoring
      7. Using pkg.go.dev
    5. Publishing Your Module
    6. Versioning Your Module
      1. Overriding Dependencies
      2. Retracting a Version of Your Module
      3. Using Workspaces to Modify Modules Simultaneously
    7. Module Proxy Servers
      1. Specifying a Proxy Server
      2. Using Private Repositories
    8. Additional Details
    9. Exercises
    10. Wrapping Up
  12. 11. Go Tooling
    1. Using go run to Try Out Small Programs
    2. Adding Third-Party Tools with go install
    3. Improving Import Formatting with goimports
    4. Using Code-Quality Scanners
      1. staticcheck
      2. revive
      3. golangci-lint
    5. Using govulncheck to Scan for Vulnerable Dependencies
    6. Embedding Content into Your Program
    7. Embedding Hidden Files
    8. Using go generate
    9. Working with go generate and Makefiles
    10. Reading the Build Info Inside a Go Binary
    11. Building Go Binaries for Other Platforms
    12. Using Build Tags
    13. Testing Versions of Go
    14. Using go help to Learn More About Go Tooling
    15. Exercises
    16. Wrapping Up
  13. 12. Concurrency in Go
    1. When to Use Concurrency
    2. Goroutines
    3. Channels
      1. Reading, Writing, and Buffering
      2. Using for-range and Channels
      3. Closing a Channel
      4. Understanding How Channels Behave
    4. select
    5. Concurrency Practices and Patterns
      1. Keep Your APIs Concurrency-Free
      2. Goroutines, for Loops, and Varying Variables
      3. Always Clean Up Your Goroutines
      4. Use the Context to Terminate Goroutines
      5. Know When to Use Buffered and Unbuffered Channels
      6. Implement Backpressure
      7. Turn Off a case in a select
      8. Time Out Code
      9. Use WaitGroups
      10. Run Code Exactly Once
      11. Put Your Concurrent Tools Together
    6. When to Use Mutexes Instead of Channels
    7. Atomics—You Probably Don’t Need These
    8. Where to Learn More About Concurrency
    9. Exercises
    10. Wrapping Up
  14. 13. The Standard Library
    1. io and Friends
    2. time
      1. Monotonic Time
      2. Timers and Timeouts
    3. encoding/json
      1. Using Struct Tags to Add Metadata
      2. Unmarshaling and Marshaling
      3. JSON, Readers, and Writers
      4. Encoding and Decoding JSON Streams
      5. Custom JSON Parsing
    4. net/http
      1. The Client
      2. The Server
      3. ResponseController
    5. Structured Logging
    6. Exercises
    7. Wrapping Up
  15. 14. The Context
    1. What Is the Context?
    2. Values
    3. Cancellation
    4. Contexts with Deadlines
    5. Context Cancellation in Your Own Code
    6. Exercises
    7. Wrapping Up
  16. 15. Writing Tests
    1. Understanding the Basics of Testing
      1. Reporting Test Failures
      2. Setting Up and Tearing Down
      3. Testing with Environment Variables
      4. Storing Sample Test Data
      5. Caching Test Results
      6. Testing Your Public API
      7. Using go-cmp to Compare Test Results
    2. Running Table Tests
    3. Running Tests Concurrently
    4. Checking Your Code Coverage
    5. Fuzzing
    6. Using Benchmarks
    7. Using Stubs in Go
    8. Using httptest
    9. Using Integration Tests and Build Tags
    10. Finding Concurrency Problems with the Data Race Detector
    11. Exercises
    12. Wrapping Up
  17. 16. Here Be Dragons: Reflect, Unsafe, and Cgo
    1. Reflection Lets You Work with Types at Runtime
      1. Types, Kinds, and Values
      2. Make New Values
      3. Use Reflection to Check If an Interface’s Value Is nil
      4. Use Reflection to Write a Data Marshaler
      5. Build Functions with Reflection to Automate Repetitive Tasks
      6. You Can Build Structs with Reflection, but Don’t
      7. Reflection Can’t Make Methods
      8. Use Reflection Only if It’s Worthwhile
    2. unsafe Is Unsafe
      1. Using Sizeof and Offsetof
      2. Using unsafe to Convert External Binary Data
      3. Accessing Unexported Fields
      4. Using unsafe Tools
    3. Cgo Is for Integration, Not Performance
    4. Exercises
    5. Wrapping Up
  18. Index
  19. About the Author

Product information

  • Title: Learning Go, 2nd Edition
  • Author(s): Jon Bodner
  • Release date: January 2024
  • Publisher(s): O'Reilly Media, Inc.
  • ISBN: 9781098139292