ads

Breaking News

হ্যাটট্রিকের সামনে দাঁড়িয়েও মেসির পেনাল্টি না নেওয়ার কারণ
মাইক্রোসফট কি টিকটককে কিনে নিচ্ছে?
Ugh PBR&B kale chips Echo Park.
মাইক্রোসফট কি টিকটককে কিনে নিচ্ছে?.
Authentic bitters seitan pug single-origin coffee whatever.
মাইক্রোসফট কি টিকটককে কিনে নিচ্ছে?
Vice mlkshk crucifix beard chillwave meditation hoodie asymmetrical Helvetica.
Ugh PBR&B kale chips Echo Park.
Gluten-free mumblecore chambray mixtape food truck.
Authentic bitters seitan pug single-origin coffee whatever.

5 Common Golang Coding Mistakes To Avoid

 Ice cream spilled on bench

Photo by Sarah Kilian on Unsplash.

Go is a simple and easy-to-learn programming language. Go programs are also pretty fast, as they are compiled down to machine code and have a static type system. Moreover, Go has built-in garbage collection and still supports pointer, pass-by-value, and pass-by-reference concepts. That is really powerful, as you don’t get restrained by the language (like with Java or other high-level programming languages).

However, it also brings a lot of confusion and leads many developers to make mistakes. In this article, we will discuss some of them.


1. Operation on Slices May or May Not Create a New Underlying Array

In Go, slices are reference types. They refer to the underlying array. When you create a new slice from an existing slice, they actually refer to the same underlying array. In the example, s1s2, and s3 all refer to the same underlying array, so when s1[2] is updated, all three slices of data are updated.

However, adding new elements to a slice may result in a new array allocation if the original array can’t hold any more new data. That is the case for s4. Therefore, we need to be very careful when working with slices, as the underlying data can be changed in a way you don’t expect.

The code below can be used to ensure we can get the reference to the new underlying array if it is allocated:

type Stack []interface{}
func (stack *Stack) Push(x interface{}) {
*stack = append(*stack, x)
}

2. The Data in the range Clause Are Copies of the Actual Collection Elements

Unlike the built-in garbage collection in most programming languages, the data values generated in the range clause in Go surprisingly do not refer to the original items. They are copies of the actual collection elements. As such, in the example above, updating the values will not change the original data. To update the original value, the index operator is needed to access them:

for i, _ : range s {
s[i].X = i
s[i].Y = i
}

3. Addressable Values vs. Unaddressable Values

Addressable values are a tricky concept in Go. We will not go into detail about the concept (you should read this article), but we will talk about how it changes our coding behaviour.

The code above can’t work, as the values in a map are not addressable and it can’t be assigned. A similar error happens to the return values from a function:

sfunc().field = .... // error when assigning struct field from func
afunc()[0] = .... // error when assigning the array item from func

In such cases, you can use a temp variable as a workaround:

Or you can use a map of pointers, as the pointer indirection is addressable:

m := make(map[string]*Point)
m["p1"] = &Point{1,1}
m["p1"].X = 2
fmt.Println(m["p1"])
--------------
&{2 1}

4. Return Pointer to Local Struct

func test() *int {
var i int = 1
return &i;
}

In C/C++, the code above can’t work, as the local variable is allocated in the stack and will be gone when the function returns. However, in Go, the compiler decides where the variable will be allocated. The compiler picks where to store the variable based on its size and the result of “escape analysis.” In this case, the compiler sees that the address of local variable i is returned, so it just makes the variable on the heap (instead of the stack).

For more details, you can read this article.

By understanding escape analysis, you can avoid some performance issues in the code, as allocating variables in a stack vs. heap gives differences in the performance.

The -m gcflag can be used in go build or go run to know where your variables are allocated (e.g. go run -gcflags -m test.go).

5. nil Checking for Pointers Can Be Confusing

Under the hood, an interface in Go can be thought of as a tuple of a value and a concrete type (an interface holds a value of a specific underlying concrete type). An interface variable that holds a nil concrete value is itself non-nil. If you want to check whether the value of the underlying type is nil, you can check like so:

np == (*int)(nil) // return true

কোন মন্তব্য নেই