Preface . . . . . . . . . . . . . . ix
1. Reading and Writing (I/O) . . . . . . . . . . 1
Using In-Memory Readers and Writers to Support
[]byte 1
Recipe 1.
Recipe 2. Compressing Old Log Files 3
Recipe 3. Using bytes.Buffer to Generate SQL 7
Recipe 4. Conditionally Decompressing Files 8
Recipe 5. Implementing io.Writer for Frequency Calculation 11
Recipe 6. Using os.Pipe for Dynamic Data Generation 13
Recipe 7. Searching in a Memory Mapped File 16
Final Thoughts 19
2. Serializing Data . . . . . . . . . . . . 21
Recipe 8. Streaming Events with encoding/gob 21
Recipe 9. Parsing Complex JSON Documents 24
Recipe 10. Streaming JSON 26
Recipe 11. Handling Missing Values in JSON 28
Recipe 12. Serializing Custom Types 30
Recipe 13. Unmarshaling Dynamic Types 32
Recipe 14. Parsing Struct Tags 34
Final Thoughts 36
3. Utilizing HTTP . . . . . . . . . . . . 37
Recipe 15. Making GET Requests 37
Recipe 16. Streaming POST Requests 41
Recipe 17. Writing Middleware to Monitor Performance 43
Recipe 18. Setting Server Timeouts 44
Recipe 19. Supporting Several API Versions in the Same
HTTP Server 45
Final Thoughts 47
4. Working with Text . . . . . . . . . . . 49
Recipe 20. Using Formatting Verbs for Better Output 49
Recipe 21. Adding String Representation to Your Types 52
Recipe 22. Detecting Encoding 54
Recipe 23. Using Regular Expressions to Convert camelCase
to lower_with_underscore 56
Recipe 24. Folding Strings for Case-Insensitive Comparison 58
Recipe 25. Using Unicode Normalization for Comparison 60
Final Thoughts 63
5. Working with Functions . . . . . . . . . . 65
Recipe 26. Using a Function Registry 65
Recipe 27. Using Functions as Options 70
Recipe 28. Using Closures to Provide Options with
Arguments 72
Recipe 29. Passing Notifications with Functions 74
Recipe 30. Accessing Unexported Functions 76
Final Thoughts 79
6. Working with Basic Types . . . . . . . . . 81
Recipe 31. Using the comma, ok Paradigm 82
Recipe 32. Using a Slice to Implement a Stack 85
Recipe 33. Calculating Cumulative Sum 89
Recipe 34. Serializing Time to/from JSON 93
Recipe 35. Using Composite Keys in Maps 96
Recipe 36. Parsing Time Strings 99
Final Thoughts 103
7. Working with Structs, Methods, and Interfaces . . . . 105
Recipe 37. Using Ad Hoc Interfaces 105
Recipe 38. Wrapping the http.ResponseWriter Interface 109
Recipe 39. Using Generics to Reduce Code Size 111
Recipe 40. Using Generics for Type-Safe Data Structures 113
Recipe 41. Using Generics for Better Type Safety 116
Final Thoughts 117
8. Working with Errors . . . . . . . . . . 119
Recipe 42. Handling and Returning Errors 119
Recipe 43. Handling Panics 121
Recipe 44. Handling Panics in Goroutines 123
Recipe 45. Checking Errors 126
Recipe 46. Wrapping Errors 128
Final Thoughts 130
9. Using Goroutines, Channels, and Context for Concurrency . 133
Recipe 47. Converting Sequential Code to Parallel 134
Recipe 48. Limiting the Number of Goroutines with
a Buffered Channel 137
Recipe 49. Using a Worker Pool with Channels 140
Recipe 50. Using context.Context for Timeouts 143
Recipe 51. Passing Logger with Request ID in Context 147
Final Thoughts 150
10. Lower-Level Concurrency . . . . . . . . . 151
Recipe 52. Writing Idempotent Functions with sync.Once 151
Recipe 53. Waiting for Job Completion with sync.WaitGroup 153
Recipe 54. Allowing Multiple Readers with sync.RWMutex 156
Recipe 55. Using the Race Detector 157
Recipe 56. Using sync/atomic for a Faster Now 162
Final Thoughts 164
11. Working with Sockets . . . . . . . . . . 165
Recipe 57. Accepting Files over TCP Sockets 165
Recipe 58. Sending Files over TCP Sockets 168
Recipe 59. Writing a Serverless Platform 170
Recipe 60. Reading Time with NTP over UDP 173
Final Thoughts 176
12. Communicating with Non-Go Code . . . . . . . 179
Recipe 61. Using os/exec to Ping Servers 180
Recipe 62. Calling C Functions to AlignText 183
Recipe 63. Redirecting Subprocess stdin and stdout
to Prototype a Calculator 185
Recipe 64. Stemming Words Using a C Library 188
Final Thoughts 191
13. Testing Your Code . . . . . . . . . . . 193
Conditionally Running Continuous Integration
Tests 193
Recipe 65.
Recipe 66. Reading Test Cases from a File 195
Recipe 67. Fuzzing Bugs Away 199
Recipe 68. Mocking HTTP Client Calls 202
Recipe 69. Writing Global Setup/Teardown Functions 205
Recipe 70. Running Services in Testing 207
Recipe 71. Writing a Linter 210
Final Thoughts 213
14. Building Applications . . . . . . . . . . 215
Recipe 72. Embedding Assets in Your Binary 215
Recipe 73. Injecting Version to Your Executable 217
Recipe 74. Ensuring Static Builds 220
Recipe 75. Using Build Tags for Conditional Builds 223
Recipe 76. Building Executables for Different Platforms 224
Recipe 77. Generating Code 227
Final Thoughts 229
15. Shipping Your Code . . . . . . . . . . 231
Recipe 78. Configuring Your Application 231
Recipe 79. Patching Dependencies 234
Recipe 80. Packaging Applications in Docker 237
Recipe 81. Catching Signals for Graceful Shutdown 239
Recipe 82. Writing Logs 241
Recipe 83. Using Metrics as Eyes to Production 243
Recipe 84. Debugging Running Services 246
Final Thoughts 249
Index . . . . . . . . . . . . . . 251
Programmers love Go because it is lightweight, easy to work with, and easy to read. Go gives you the benefits of dynamically typed languages (speed of development) while keeping the upsides of strongly typed languages (security and performance).
Go is a simple language, but programming in Go is about more than just mastering syntax. There's an art to using Go effectively. Squeeze out the full use of advanced networking and multi-core power for which Go was designed. Save precious coding hours with recipes that help you manage objects, collect garbage, and safely use memory. Tackle Unicode, concurrency, and serialization with ease.
All the clean, reusable solutions you need for a wide variety of problems common to Go development. Outfitted with these recipes, your next apps will be more polished and more maintainable than ever.
Start out by tackling time and see how the Go time packager provides types that will do most of the heavy lifting for you. Next, work on recipes tailored to the nuances of processing text, like normalizing strings to avoid bugs. From there, whip up some functions on-the-fly and store functions in variables and data structures.
Ever wondered why Go seems to be peppered with error handling? Working through the next recipes, you'll discover the benefits, which include more robust code. In the section on HTTP, you'll learn tricks like running multiple HTTP servers on the same port and setting timeouts. With concurrency recipes, you'll limit the number of goroutines to improve performance, give your code awareness of timeouts, and decide when to keep your code sequential instead of making it concurrent.
Throughout the book, you'll make Go sizzle following simple recipes and tweaking them to fit your own apps. Using tools like strong typing and concurrency primitives, build a Go codebase that stays maintainable at scale.
You should know the Go language syntax and have some experience in programming. You will need a Go SDK, a Git client, and for some of the chapters, a C compiler.