50-Mistake-Golang
50 Common Mistakes in Go Development
Go is a powerful and concise language, but its simplicity can lead to subtle mistakes, especially for developers new to its paradigms. This guide outlines 50 common pitfalls in Go development, with explanations and examples to help you write robust and idiomatic Go code. These mistakes are derived from common errors observed in the Go community, translated and adapted from the referenced source.
1. Left Curly Brace on a New Line
Go’s syntax requires opening curly braces ({) to be on the same line as the statement. A newline before { causes a compilation error.
// Wrong
func main()
{
fmt.Println("Hello")
}
// Correct
func main() {
fmt.Println("Hello")
}2. Unused Variables
Go disallows unused variables to enforce clean code. Declared variables must be used, or the code won’t compile.
// Wrong
func main() {
x := 10 // Error: x declared but not used
}
// Correct
func main() {
x := 10
fmt.Println(x)
}Use _ for variables you intentionally ignore, like loop indices or return values.
3. Unused Imports
Unused import statements cause compilation errors. Remove or use imported packages.
Use goimports to automatically manage imports.
4. Short Variable Declarations Only in Functions
The := operator for short variable declarations is only valid inside functions, not at package level.
5. Redeclaring Variables with :=
:=Short declarations (:=) cannot redeclare variables in the same block if they’re already declared, unless at least one new variable is introduced.
6. Accidental Variable Shadowing
Short declarations in inner scopes can shadow outer variables, leading to unexpected behavior.
Use = to assign to the outer variable or avoid redeclaring.
7. Misusing nil Slices
nil SlicesA nil slice has len=0, cap=0, and can be appended to, but developers may assume it’s invalid.
Check for nil explicitly only when necessary, as len(s) == 0 is usually sufficient.
8. Appending to a Slice Without Checking Capacity
Appending to a slice may reallocate the underlying array if capacity is exceeded, affecting performance.
Preallocate capacity with make when the size is predictable.
9. Modifying Slices Sharing the Same Array
Slices referencing the same underlying array share modifications, which can lead to bugs.
Use copy to create independent slices.
10. Incorrect Slice Capacity in Reslicing
Reslicing with s[i:j:k] sets cap = k-i. Misjudging k can limit future appends.
11. Ignoring Return Values
Go functions often return multiple values (e.g., result and error). Ignoring them can hide issues.
12. Misusing defer
deferThe defer statement delays execution until the surrounding function returns, but arguments are evaluated immediately.
Use a closure to capture the current state.
13. Multiple defer Order
defer OrderDeferred functions execute in LIFO (last-in, first-out) order.
14. Panic in Deferred Functions
A panic in a deferred function can overwrite an earlier panic, complicating debugging.
Use recover carefully to handle panics.
15. Incorrect recover Usage
recover Usagerecover only works in deferred functions and captures panics in the current goroutine.
16. Goroutines Without Synchronization
Goroutines run concurrently, and unsynchronized access to shared variables causes race conditions.
Use sync.Mutex or channels for synchronization.
17. Goroutines Leaking
Goroutines that never exit (e.g., blocked on channels) can leak memory.
Use context cancellation or close channels to signal exit.
18. Closing Unbuffered Channels
Closing an unbuffered channel before a receiver is ready causes a panic.
Ensure receivers are ready or use buffered channels.
19. Sending to a Closed Channel
Sending to a closed channel causes a panic.
Check if a channel is closed using a select or boolean flag.
20. Misusing Buffered Channels
Buffered channels can block if full, leading to deadlocks if not handled.
Monitor buffer size or use non-blocking sends with select.
21. Incorrect Range Over Channels
Ranging over a channel continues until the channel is closed.
Always close channels when done sending.
22. Nil Channels
Sending or receiving on a nil channel blocks forever.
Initialize channels with make before use.
23. Incorrect Interface Assertions
Type assertions on interfaces can panic if the type doesn’t match.
Use the comma-ok idiom to check safely.
24. Empty Interface Misuse
Using interface{} sacrifices type safety and can lead to runtime errors.
Prefer specific interfaces or generics (Go 1.18+).
25. String Conversion Errors
Converting non-numeric strings to integers with strconv.Atoi returns an error that must be checked.
Always handle errors.
26. Incorrect String Concatenation
Repeated string concatenation in a loop is inefficient due to immutability.
Use strings.Builder for efficiency.
27. Map Initialization
Using an uninitialized map (var m map[K]V) causes a panic on write.
Initialize with make or a literal.
28. Map Iteration Order
Map iteration order is random by design, which can surprise developers expecting consistency.
Sort keys explicitly if order matters.
29. Concurrent Map Access
Maps are not safe for concurrent writes.
Use sync.RWMutex or sync.Map for concurrency.
30. Incorrect Map Deletion
Deleting from a map with a non-existent key is safe but has no effect.
Check existence with the comma-ok idiom if needed.
31. Incorrect Struct Field Access
Accessing unexported fields (lowercase) from another package causes compilation errors.
Use exported fields (uppercase).
32. Struct Copy Semantics
Structs are copied by value, which can lead to unexpected behavior.
Use pointers for shared modifications.
33. JSON Marshalling Unexported Fields
Unexported struct fields are ignored during JSON marshalling.
Use exported fields for JSON.
34. Incorrect Time Comparison
Comparing time.Time values with == checks both time and location.
Use Equal for time comparison.
35. Time Parsing Errors
Parsing invalid time strings with time.Parse returns an error that must be checked.
Always handle errors.
36. Incorrect Error Wrapping
Using fmt.Errorf without wrapping the original error loses context.
Use %w to wrap errors (Go 1.13+).
37. Ignoring Context Cancellation
Ignoring context.Context cancellation can lead to resource leaks.
Check ctx.Done().
38. Incorrect HTTP Handler Registration
Registering HTTP handlers with the same path overwrites earlier handlers.
Use a router like http.ServeMux carefully.
39. HTTP Server Shutdown
Not shutting down HTTP servers gracefully can drop connections.
Use http.Server.Shutdown.
40. Incorrect File Closing
Not closing files can leak resources.
Use defer to close.
41. Incorrect Loop Variable Capture
Loop variables in closures (e.g., goroutines) are reused, causing unexpected behavior.
Copy the loop variable.
42. Incorrect Array vs. Slice
Arrays ([n]T) and slices ([]T) have different behaviors. Arrays are fixed-size and copied by value.
43. Incorrect Pointer Receiver
Using value receivers in methods prevents modifying the receiver.
Use pointer receivers.
44. Nil Pointer Dereference
Dereferencing a nil pointer causes a panic.
Check for nil before dereferencing.
45. Incorrect Method Expression
Using method expressions requires explicit receiver passing.
46. Incorrect Interface Implementation
A type must implement all methods of an interface, including pointer vs. value receiver nuances.
47. Incorrect Slice Initialization
Slices must be initialized before use, but make syntax varies.
Use correct make arguments.
48. Incorrect Range Over Strings
Ranging over a string iterates over bytes, not runes, which can break UTF-8 handling.
Use []rune for rune iteration.
49. Incorrect Signal Handling
Not handling OS signals can prevent graceful shutdown.
Use os/signal.
50. Ignoring Go’s Simplicity
Overcomplicating solutions with unnecessary abstractions violates Go’s philosophy of simplicity.
Embrace straightforward, idiomatic Go.
Conclusion
These 50 mistakes cover syntax, concurrency, memory management, and idiomatic practices critical for Go development. By understanding these pitfalls and their solutions, you can write cleaner, more efficient, and maintainable Go code. Refer to the Go documentation and tools like go vet, golint, and golangci-lint to catch these issues early.
Last updated