Golang Tutorial
Introduction Variables Constants Data Type Convert Types Operators If..Else Switch..Case For Loops Functions Variadic Functions Deferred Functions Calls Panic and Recover Arrays Slices Maps Struct Interface Goroutines Channels Concurrency Problems Logs Files and Directories Reading and Writing Files Regular Expression Find DNS records Cryptography Gotchas in Golang Import and Export Best Golang Packages Web Application Goroutines and Channels Exercises Reflection in Golang Golang for beginners Strings in Golang HTTP Client Server Examples Context PackageGolang Reference
Basic Programs Advance Programs Data Structure and Algorithms Date and Time Slice Sort, Reverse, Search Functions String Functions Methods and Objects Interface TypeBeego Framework
Beego Setup Beego Database Migration Beego GET POST Beego RoutingGotchas in Golang
Golang Gotchas
Writing programs that work when everything goes as expected is a good start. Making your programs behave properly when encountering unexpected conditions is where it really gets challenging.
Even seasoned Gopher can get trapped in one of the many pitfalls of the Go language. But there are some cases which might confuse or rather trick a rookie coder. These are called "Gotchas"! Originating from the informal term "Got You!", a gotcha is a case or scenario when the program plays the trick and results in an output that is quite different from what was expected.
The list of common gotchas is far from exhaustive, and is presented in no particular order of severity.
Mismatched types int and float64
The Go type system will not allow any mathematical operation between integer and float variables.
Fails
package main
import "fmt"
func main() {
var x, y = 13, 3.5
fmt.Println(x / y)
}
Error
.\error-1.go:7:16: invalid operation: x / y (mismatched types int and float64)
What do you think will be the output of the following program?
Works
package main
import "fmt"
func main() {
var x = 13 / 3.5
fmt.Println(x)
}
In the above program, the right side of = are constants, not variables. Hence compiler will convert 13 into a float type to execute the program. This program will print the output −
Output
3.7142857142857144
Example
package main
import "fmt"
func main() {
var x, y = 13, 3.5
fmt.Println(float64(x) / y)
}
Use float64 to convert type of x into float64.
Assignment to entry in nil map
Map types are reference types, like pointers or slices, and so the value of rect is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that.
Fails
package main
import "fmt"
func main() {
var rect map[string]int
rect["height"] = 10
fmt.Println(rect["height"])
}
Error
panic: assignment to entry in nil map
What do you think will be the output of the following program?
Works
package main
import "fmt"
func main() {
var rect map[string]int
fmt.Println(rect["height"])
fmt.Println(len(rect))
idx, key := rect["height"]
fmt.Println(idx)
fmt.Println(key)
}
The Zero Value of an uninitialized map is nil. Both len and accessing the value of rect["height"] will work on nil map. len returns 0 and the key of "height" is not found in map and you will get back zero value for int which is 0. Similarly, idx will return 0 and key will return false.
Output
0
0
0
false
Works
package main
import "fmt"
func main() {
var rect = map[string]int{"height": 10}
fmt.Println(rect["height"])
}
You can also make a map and set its initial value with curly brackets {}.
Raw string literals vs Interpreted string literals
There are two different ways to represent string literals.
Example
package main
import "fmt"
func main() {
s := `Go\tJava\nPython`
fmt.Println(s)
}
What do you think will be the output of the above program?
Output
Go\tJava\nPython
Raw strings are enclosed in back-ticks `. Here, \t and \n has no special meaning, they are considered as backslash with t and backslash with n. If you need to include backslashes, double quotes or newlines in your string, use a raw string literal.
Example
package main
import "fmt"
func main() {
s := "Go\tJava\nPython"
fmt.Println(s)
}
Raw strings are enclosed in quotes ". Hence \t would be interpreted as tab and \n as new line. The above program will print,
Output
Go Java
Python
Invalid operation mismatched types Int and Time.Duration
The operands to numeric operations must have the same type unless the operation involves shifts or untyped constants.
Fails
package main
import (
"fmt"
"time"
)
func main() {
var timeout = 3
fmt.Println(timeout)
fmt.Println(timeout * time.Millisecond)
}
Error
.\error-1.go:11:22: invalid operation: timeout * time.Millisecond (mismatched types int and time.Duration)
What do you think will be the output of the following program?
Works
package main
import (
"fmt"
"time"
)
func main() {
const timeout = 10
fmt.Println(timeout)
fmt.Println(timeout * time.Millisecond)
}
Millisecond's underlying type is an int64, which the compiler knows how to convert to. Literals and constants are untyped until they are used, unless the type is explicitly declared. timeout is an untyped constant in this example. Its type is implicitly converted to time.Millisecond. This program will print the output −
Output
10
10ms
Example
package main
import (
"fmt"
"time"
)
func main() {
var timeout time.Duration
timeout = 10
fmt.Println(timeout * time.Millisecond)
}
Define the type of timeout as time.Duration.
String Length Bytes vs Runes
When you ask the length of string in Go, you will get the size in bytes.
Example
package main
import "fmt"
func main() {
data := "We♥Go"
fmt.Println(len(data))
}
What do you think will be the output of the above program?
Output
7
If you count the number of charcters is "We♥Go", it would be 5. So why 7?
In Go Strings are UTF-8 encoded, this means each charcter called rune can be of 1 to 4 bytes long. Here,the charcter ♥ is taking 3 bytes, hence the total length of string is 7.
Example
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
data := "We♥Go"
fmt.Println(utf8.RuneCountInString(data))
}
If you want to get the number of runes in the string, you can use the unicode/utf8 package. The RuneCountInString function will return number of runes in a string. The above program will print,
Output
5
Initialize variable with nil
Nil is not a type but a reserved word, you cannot use it in assignment.
Fails
package main
import (
"fmt"
)
func main() {
var data string = nil
if data == nil {
fmt.Println(data)
}
}
Output
cannot use nil as type string in assignment
What do you think will be the output of the following program?
Works
package main
import (
"fmt"
)
func main() {
var data *string = nil
if data == nil {
fmt.Println(data)
}
}
*string is the type of the pointer variable which points to a value of type string. The zero value of a pointer is nil.
Output
nil
Floating point multiplication
Floating-point arithmetic is considered an esoteric subject by many people.
Example
package main
import (
"fmt"
)
func main() {
var m = 1.39
fmt.Println(m * m)
const n = 1.39
fmt.Println(n * n)
}
What do you think will be the output of the following program?
Output
1.9320999999999997
1.9321
This is rather surprising because floating-point is ubiquitous in computer systems. Almost every language has a floating-point datatype; computers from PCs to supercomputers have floating-point accelerators; most compilers will be called upon to compile floating-point algorithms from time to time; and virtually every operating system must respond to floating-point exceptions such as overflow.
T is a floating-point type and n can be rounded to T's precision without overflow. Rounding uses IEEE 754 round-to-even rules but with an IEEE negative zero further simplified to an unsigned zero. Note that constant values never result in an IEEE negative zero, NaN, or infinity.
String type conversion
Go doesn't allow automatic type promotion between variables. You must use a type conversion when variable types do not match.
Fails
package main
import "fmt"
func main() {
i := 105
s := string(i)
fmt.Println(s)
}
What do you think will be the output of the above program?
Output
i
The string supports type conversion from int, here string() will treat integer as rune. The rune of 105 is i.
Works
package main
import (
"fmt"
"strconv"
)
func main() {
i := 105
s := strconv.Itoa(i)
fmt.Println(s)
s = fmt.Sprintf("%d", i)
fmt.Println(s)
}
To convert an integer variable into String use any either strconv.Itoa() or fmt.Sprintf() function.
Output
105
105
Unused Variables vs Unused Constants
Go has some rules that are unique among programming languages.
Example
package main
func main() {
var i = 100
}
Output
i declared and not used
If you have unused variables, the code will not compile. If you assign a value to an unused variable, still your code will not compile. We'll have to use it somewhere to please the compiler.
Example
package main
func main() {
const i = 100
}
The above program won't print any exception or error. This is because constants in Go are calculated at compile time and cannot have any side-effects. This makes them easy to eliminate and they are not included in the compiled binary.