Background about me as the reviewer: I'm primarily a Python programmer. I've been writing Go programs for over 5 years now (my first commit). I've used Go in side projects and a bit at work (full disclosure: I work at Google). I've written about using Go in my free time. I went to the first GopherCon. Go is my choice of programming language for CPU-bound workloads. Somewhat related: I've written a book about a programming language before (full disclosure: also published by Addison-Wesley), so I'm reasonably equipped to write a review.
Overall: It's a great book. Even though I'm already quite familiar with Go, I found reading the book to be a good use of my time. Practical knowledge I have from using Go was reinforced with a deeper level of understanding thanks to the book. I expected a lot, given the authors' pedigree, and the book lived up to it.
Some key points for potential readers:
- Not for first-time programmers. This is an introduction to Go, not to programming.
- Contains well-written, short, clear example code that motivates the information being presented.
- Provides realistic exercises at the end of each section to help you practice.
- Goes into important detail and subtlety without reading like a language specification.
Here's one example of the type of detail in the book that I really appreciate:
Before we go further, we should explain one subtlety in what it means for a type to have a method. Recall from Section 6.2 that for each named concrete type T , some of its methods have a receiver of type T itself whereas others require a *T pointer. Recall also that it is legal to call a *T method on an argument of type T so long as the argument is a variable; the compiler implicitly takes its address. But this is mere syntactic sugar: a value of type T does not possess all the methods that a *T pointer does, and as a result it might satisfy fewer interfaces.
And here's another:
In this respect, interface types are unusual. Other types are either safely comparable (like basic types and pointers) or not comparable at all (like slices, maps, and functions), but when comparing interface values or aggregate types that contain interface values, we must be aware of the potential for a panic. A similar risk exists when using interfaces as map keys or switch operands. Only compare interface values if you are certain that they contain dynamic values of comparable types.
This type of precise and succinct description is so valuable. In this book, such prose is almost always paired with a code example illustrating the point, in case you don't get it. This level of rigor you won't find in a beginner book. More advanced books, guides, and blog posts sometimes have this detail, but it's usually too verbose or sloppy to be clear. Well done!
In conclusion: If you want to improve your Go, this book is worth checking out.