First thing is first. Happy New Years 🎉🎉
Now that’s out of the way, let’s talk about Go. I recently finished learning my basic perliminary real Go program. The process was quite fun and I learned a lot about Go in the process. So, to wrap up my first official foray into Rob Pike’s mystical land of gophers, I decided to write down some of the common “Gotchas!” that any beginning Gopher - like me - can run into.
Gophers can be quite aggressive sometimes
The range function is one of the most commonly used functions in Go. Here’s a sample use case of the range function. Note that for some demented reason, we decided to make all the animals in the zoo have 999 legs.
type Animal struct {
name string
legs int
}
func main() {
zoo := []Animal{ Animal{ "Dog", 4 },
Animal{ "Chicken", 2 },
Animal{ "Snail", 0 },
}
fmt.Printf("-> Before update %v\n", zoo)
for _, animal := range zoo {
// 🚨 Oppps! `animal` is a copy of an element 😧
animal.legs = 999
}
fmt.Printf("\n-> After update %v\n", zoo)
}
The above code looks innocent enough. However, you may be surprised to find that the two fmt.Printf() statements yield the same results.
-> Before update [{Dog 4} {Chicken 2} {Snail 0}]
-> After update 🚨🚨🚨 [{Dog 4} {Chicken 2} {Snail 0}]
Value property of range (stored here as animal) is a copy of the value from zoo, not a pointer to the value in zoo.
In order to modify an element within the array, we must change the element via its pointer.
for idx, _ := range zoo {
zoo[idx].legs = 999
}
This may look quite trivial but you may be surprised to find this as a one of the most common source of bugs; at least for me!
» Go playground #1 for you to play around in
You may have used the … keyword in the C programming language to create a variadic function; variadic function is a function that takes a variable number or type of arguments.
In C, you have to successively call the va_arg macro in order to access the optional arguments. And if you use the variadic argument in any other way, the compiler will throw an error.
int add_em_up (int count,...) {
...
va_start (ap, count); /* Initialize the argument list */
for (i = 0; i < count; i++)
sum += va_arg(ap, int); /* Get the next argument value */
va_end (ap); /* Clean up */
return sum
}
In Go however, things are similar but quite different at the same time. Here is a variadic function myFprint in Go. Notice how the variadic argument a is being used.
func myFprint(format string, a ...interface{}) {
if len(a) == 0 {
fmt.Printf(format)
} else {
// ⚠️ `a` should be `a...`
fmt.Printf(format, a)
// ✅
fmt.Printf(format, a...)
}
}
func main() {
myFprint("%s : line %d\n", "file.txt", 49)
}
Output:
[file.txt %!s(int=49)] : line %!d(MISSING)
file.txt : line 49
You’d think that the compiler would throw an error here for using the variadic parameter a in a wrong way. But notice how fmt.Sprintf just used the first argument in a without throwing a fit.
In Go, variadic parameters are converted to slices by the compiler
» Go playground #2 for you to play around in
If you have done your fair share of slicing in Python, you may remember that slicing in Python gives you a new list with just the references to the elements copied over. This property allows for code like this in Python.
a = [1, 2, 3]
b = a[:2] # 👀 a completely new list!
b[0] = 999
>>> a
[1, 2, 3]
>>> b
[999, 2]
However if you try the same thing in Go, you get something else.
func main() {
data := []int{1,2,3}
slice := data[:2]
slice[0] = 999
fmt.Println(data)
fmt.Println(slice)
}
Output:
[999 2 3]
[999 2]
In Go, a slice shares the same backing array and capacity as the original. So if you change an element in the slice, the original contents are modified as well.
If you want to get an independent slice, you have two options.
// Option #1
// appending elements to a nil slice
// `...` changes slice to arguments for the variadic function `append`
a := append([]int{}, data[:2]...)
// Option #1
// Create slice with length of 2
// copy(dest, src)
a := make([]int, 2)
copy(a, data[:2])
And according to StackOverflow, the append option is slightly faster than the make. + copy
option!
» Go playground #3 for you to play around in
Machine Learnig Enthusiast
© 2018 Shabbir Hasan