The Go Optimizations 101, Go Details & Tips 101 and Go Generics 101 books are all updated to Go 1.25. The most cost-effective way to get them is through this book bundle in the Leanpub book store.
If you would like to learn some Go details and facts every serveral days, please follow @zigo_101.
I just read an article: 15 Go Subtleties You May Not Already Know. After reading that article, I just feel the title is some weird/improper. Because all the so-called subtleties mentioned in that article are what a qualified Go programmer should know about.
Go indeed has many subtleties. Even many professional Go programmers are not aware of some of them. Here, this article shows several of them (all of them are from the Go Details & Tips 101 book).
Contents:
- Comparing two pointers to zero-size values might result either true or false, even during the same program execution
for true {...}andfor {...}are not equivalent- When using the
makebuilt-in function to create a map, the second argument (cap) can be negative aConstantString[:]is not a constant- If the left operand of a non-constant bit-shift expression is untyped, then its type is determined as the assumed type of the expression
For example. What does the following program print? Nothing or true?
package main
var a, b [0]int
var p, q = &a, &b
func main() {
if (p == q) {
p, q = &a, &b
println(p == q)
}
}
It prints false (with the official Go toolchain). Surprised? But it looks the behavior doesn't violate Go specification.
A similar one:
package main
var a, b struct{}
var p, q = &a, &b
func main() {
var p2, q2 = &a, &b
println(p == q) // true
println(p == p2) // true
println(q == q2) // true
println(p == q2) // true
println(q == p2) // true
println(p2 == q2) // false
}
For example, the function foo shown below compiles, but bar doesn't.
func foo() int {
for {}
}
func bar() int {
for true {}
}
For example, the following code compiles.
package main
var n = -100
func main() {
var m = make(map[int]bool, n)
m[123] = true;
}
A negative cap argument is equivalent to omitting it.
Here is an example to prove it.
package main
const s = "zigo 101" // len(s) == 8
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
func main() {
println(a, b) // 2 0
}
Some Go programmers might be surprised by this result. To understand the result well, we need to know about the next subtlety.
For example, the following program prints 0 0 2.
package main
const N = 8
var n = N
func main() {
var x byte = 1 << n / 128
var y = byte(1 << n / 128)
var z byte = 1 << N / 128
println(x, y, z) // 0 0 2
}
In the first two declarations, the types of 1 are both assumed as byte. So the two declarations are both equivalent to the following line, in which the run-time expression byte(1) << n overflows (and is truncated to 0).
... = byte(1) << n // 128
The last declaration is equivalent to the following line. The expression 1 << N / 128 is evaluated at compile time. In the expression, 1 is treated as untyped int value.
var z = 2
The Go 101 project is hosted on GitHub. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
Tapir, the author of Go 101, has been on writing the Go 101 series books since 2016 July.
New contents will be continually added to the books (and the go101.org website) from time to time.
Tapir is also an indie game developer.
You can also support Go 101 by playing Tapir's games: