golang gotchas: 10 common pitfalls and how to avoid them

An introduction to the Go programming language and its common pitfalls.

Go (or Golang) is an open source programming language designed for building simple, fast and reliable software.

10 common gotchas in golang

  1. Unused Variables Cause Compile Errors

    • Go does not allow unused variables or imports. Remove or use them to avoid errors.
    1
    2
    3
    
    func main() {
        x := 5 // Error: x declared but not used
    }
    
  2. Short Variable Declarations (:=) Only for New Variables

    • Using := with an existing variable in the same scope will not reassign it, but create a new one if possible.
    1
    2
    
    x := 1
    x := 2 // Error: no new variables on left side of :=
    
  3. Nil Slices vs. Empty Slices

    • A nil slice (var s []int) is different from an empty slice (s := []int{}). Some functions may behave differently.
    1
    2
    3
    4
    
    var a []int      // nil slice
    b := []int{}     // empty slice
    fmt.Println(a == nil) // true
    fmt.Println(b == nil) // false
    
  4. Maps Are Not Safe for Concurrent Use

    • Accessing or writing to a map from multiple goroutines without synchronization will cause a runtime panic.
    1
    2
    3
    4
    
    m := make(map[string]int)
    go func() { m["a"] = 1 }()
    go func() { m["b"] = 2 }()
    // May panic: fatal error: concurrent map writes
    
  5. Defer Statements Are Executed in LIFO Order

    • Deferred functions run after the surrounding function returns, in last-in, first-out order.
    1
    2
    3
    4
    5
    
    func main() {
        defer fmt.Println("first")
        defer fmt.Println("second")
    }
    // Output: second\nfirst
    
  6. Loop Variable Capture in Goroutines

    • Loop variables are reused in each iteration. Use a local variable inside the loop when launching goroutines.
    1
    2
    3
    4
    5
    6
    7
    8
    
    for i := 0; i < 3; i++ {
        go func() { fmt.Println(i) }() // All goroutines may print 3
    }
    // Correct way:
    for i := 0; i < 3; i++ {
        v := i
        go func() { fmt.Println(v) }()
    }
    
  7. Interface Nil vs. Typed Nil

    • An interface holding a typed nil value is not itself nil. This can cause unexpected behavior in nil checks.
    1
    2
    
    var err error = (*os.PathError)(nil)
    fmt.Println(err == nil) // false
    
  8. Strings Are Immutable

    • You cannot modify a string in place. Convert to a slice of bytes or runes to manipulate.
    1
    2
    3
    4
    5
    
    s := "hello"
    // s[0] = 'H' // Error: cannot assign to s[0]
    b := []byte(s)
    b[0] = 'H'
    s2 := string(b) // "Hello"
    
  9. No Implicit Type Conversions

    • Go does not automatically convert between types (e.g., int to float64). You must cast explicitly.
    1
    2
    
    var x int = 5
    var y float64 = float64(x) // Explicit conversion
    

Exported Names Must Start with a Capital Letter * A Capital letter** is used to start by **Export Name’s MUST BEGIN. - Only identifiers starting with an uppercase letter are exported from a package.

```go
// In package foo
var Bar = 1 // Exported
var baz = 2 // Not exported
```

Keep these in mind to avoid common pitfalls when working with Go!

Built with Hugo
Theme Stack designed by Jimmy