Top 10 Common Mistakes In Go Programming

Top 10 Common Mistakes In Go Programming

Go is a popular and trendy programming language. But Go developers often face particular common bugs and errors. Developers address them as Gotchas. Golang is a comparatively new programming language by Google. Native gophers often face these pitfalls, so here we came with some common mistakes and its solutions. Checkout the following Gotchas and if you have already come across them in Go programming journey, know the solutions of it.

Top 10 Common Mistakes In Go Programming-

1. Multiple-value in single-value context-

Issue-

 t  := time.Parse(time.RFC3339, “2018-04-06T10:49:05Z”)
fmt.Println(t)
../main.go:9:17: multiple-value time.Parse() in single-value context

When you try to parse the date and time, you get a compiler error.

Solution-

 t, err := time.Parse.RFC3339, “2018-04-06T10:49:05Z”)
  if err != nil {
      // TODO: Handle error.
}
fmt.Println(t)
2018-04-06 10:49:05 +0000 UTC

The parse function with time returns a time value and error value, and explicitly you need to use them. Or To ignore the unwanted error values, you can use a blank identifier _as below:

 m := map[string]float64{“pi”: 3.1416}
_, exists := m[“pi”] // exists == true

2. Possibly undesired value being used in goroutine-

Range variables in a loop are reused at each iteration; so, a goroutine created in a loop will point to the range variable from upper scope. In this way, the goroutine could use the variable with an undesired value. As per the below example, value of index and value used in goroutine are from the outer scope because goroutines run asynchronously, the value of index and value could be (and usually are) different from the intended value.

mySlice := []string{"A", "B", "C"}
for index, value := range mySlice {
go func() {
fmt.Printf("Index: %d\n", index)
fmt.Printf("Value: %s\n", value)
}()
}

To overcome this problem, a local scope should be created, like in the example below.

mySlice := []string{"A", "B", "C"}
for index, value := range mySlice {
  index := index
 
   value := value
go func() {
fmt.Printf("Index: %d\n", index)
fmt.Printf("Value: %s\n", value)
}()
}

Another approach to deal with this could be by passing the values as args to the goroutines.

mySlice := []string{"A", "B", "C"}
for index, value := range mySlice {
go func(index int, value string) {
fmt.Printf("Index: %d\n", index)
fmt.Printf("Value: %s\n", value)
}(index, value)
}

3. Nil pointer dereference-

Most of the time Go-developers face the issue of dereferencing of a nil pointer. Let’s check the issue-

 type Point struct {
     X, Y float64
}
Func (p *Point) Abs() float64 {
         Return math.Sqrt(p.X*p.X + p.Y*p.Y)
}
 func  main() {
            var p *Point
           fmt.Println(p.Abs())
}
Panic: runtime error: invalid memory address or nil dereference [signal] SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xd2c5a]
 
goroutine 1 [running]:
main.(*Point).Abs(...)
         ../main.go:6
main.main()
        ../main.go:11 +0x1a 

Pointer in the main function (p) is nil, so you can not follow the nil pointer as it causes run-time error.

Solution-

func main() {
         var p *Point = new(Point)
         fmt.Println(p.Abs())
}

Either you can create a new Pont as mentioned in above snippet. Or Methods with pointer receivers either need a value or a pointer, so try this-

func main() {
var p Point //has zero value Point{X.0, Y.0}
fmt.Println(p.Abs())
}

4. Regular expression mismatch-

When using Go, most of the regular expressions function in the package use substring matching. 

Issue:

matched, err := regexp.MatchString(‘[0-9]*’, “12three45”)
fmt.Println(matched) //true
fmt.Println(err)    // nil (regexp is valid)

It matches characters in the string, that we do not intend. 

Solution-

To overcome the issue, you can anchor the beginning and end of the string with caret ^ and dollar $ signs.

matched, err := regexp.MatchString(‘[0-9]*’, “12three45”)
fmt.Println(matched)  // true
fmt.Println(err)           //nil (regexp is valid)

Now, you know the working of magic with words, in Golang too.

5. Infinite recursive call-

Function that calls itself recursively should have an exit condition. Else it will recurse forever till the system runs out of memory. This issue can be caused by common mistakes like forgetting to add an exit condition. Also, it can happen “on purpose”. Some of the languages have tail-call optimization, that makes certain infinite recursive calls safe to use. Tail-call optimization lets you to avoid allocating a new stack frame for a function called calling function will return the value that it gets from the called function.

Common use is tail-recursion, where a recursive function written to leverage tail-call optimization can use constant stack space. But, this isse doesn’t apply to spawning new goroutines.

6. Closure and iteration variable –

There is a competition between two goroutines when they access the same variable at the same time, and one of the accesses is ‘write’. 

Issue:

func main() {
   var wg sync.WaitGroup
   wg.Add(5)
   for i := 0; i < 5; i++ {
          go func() {
                fmt.print(i)
                wg.Done()
}()
}
wg.Wait()
fmt.Println()
}

This produces the output as follows-

55555

Solution-

Variable i accessed by six goroutines. So, rather than i, one can use local variable n:

func main() {
    Var wg sync.WaitGroup
     wg.Add(5)
     for i := 0; i < 5; i++ {
         go func(n int) { // Use a local variable.
          fmt.Print(n)
          wg.Done()
}(i)
}
wg.Wait()
 fmt.Println()
}

Sorted result-

40123

Or To avoid this data race, also, you should use unique variable for each goroutine.

func main() {
   var wg sync.WaitGroup
   wg.Add(5)
   for i := 0; i < 5; i++ {
    n := i //create a unique variable for each closure
go func() {
  fmt.Print(n)
  wg.Done()
}()
}
wg.Wait()
fmt.Println()
}

7. JSON not visible –

Unexpectedly, you get to see an empty JSON object in Go.

Issue:

type Person struct {
   name string
   age int
}

p := Person{“Alice”, 22}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData))

{}

Solution- 

You have to export JSON values.

type Person struct {
   Name string // Changed to capital N
   Age int        // Changed to capital A
}

P := Person{“Alice”, 22}

jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData))

{“Name” :”Alice”, “Age” :22}

Or use naming the JSON values with a tag.

type Person struct {
   Name string ‘json:”name”’
   Age int ‘json:”age”’
}
p := Person{“Alice”, 22}

jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData))

{“name”:”Alice”,”age”:22}

8. Iteration variable of range loop unchangeable-

Iteration variable is unaware if an array value changes

Issue:

var a [2]int
for _, x := range a {
   fmt.Println(“x =”, x)
    A[1] = 8
}
fmt.Println(“a =”, a)
x = 0
x = 0    <- why this is not 8?
a = [08]

Solution: 

You can iterate the values over slice rather than array.

var a [2]int
for _, x := range a[:] {
   fmt.Println(“a =”, a)

x = 0
x = 8
a = [0 8]

9. Index out of range-

In Go, indexing starts from zero. 

Issue:

 a := [ ]int{1, 2, 3}
for i := 1; i <= len(a); i++ {
   fmt.Println(a[i])
} 

panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
   ../main.go:3 +0xe0

The above program will crash. Solution to this is-

The value of a are placed at a[0], a[1], a[2], …., a[len(a)-1].

for i :=0; i < len(a); i++ {
   fmt.Println(a[i])
}

Or one can use a range loop:

for _, n := range a {
    fmt.Println(n)
}

10. Unexpected ++ 

Sometimes Go programmers troubles issue with pre and post incrementation.

Issue:

i := 0
fmt.Println(++i)
fmt.Println(i++)

main.go:9:14: syntax error: unexpected ++, expecting expression
main.go:10:15: syntax error: unexpected ++, expecting comma or )

Solution-

In Go, one can use increment and decrement operations as statements and not expressions.

i := 0
i++
fmt.Println(i)
fmt.Println(i)
i++

You can also know- Why Golang Is Better Than Other Languages?

Wrap up-

These are just some of the common mistakes in Go programming. There can be few others too. If you’re thinking of selecting Go language for your next project, knowing these common mistakes and its solutions will help you in bug free Go development. In case any difficulty with Go programming, consult with Solace experts. We offer Go development expertise to build your scalable web architecture. Feel free to contact us for an effective and bug free go development. We will be happy to help you.

Related Post