I read this book (PR) right after The Rust Programming Language (TRPL). Please be aware that I wasn’t approaching PR with the same fresh innocence as I had TRPL, and although I have tried not to allow this to colour my review, I am not sure that I have succeeded completely.
This book begins, appropriately enough with a short chapter entitled ‘Why Rust?’. As expected, this stresses Rust’s emphasis on type-safety. Less expected was the categorization of Rust as specifically a systems programming language – I’d view it as being just as suitable for applications work. The point being made is that efficient close-to-the-metal languages like C and C++ that are typically used for systems work are significantly less typesafe than ‘softer’ languages like Python. As a C++ programmer, I found the comparison rankled, but the authors do have a point.
The second chapter provides a whistle-stop tour of Rust, touching on a great many language features without really explaining any. This is exactly what I complained about in TRPL, but that doesn’t seem to matter here: the presentation makes it clear that the tour is merely a preview to whet the readers’ appetites – like a trailer in the cinema. It’s a flourish of special effects and we’re not supposed to be able to deduce the whole plot from it.
Chapter 3 begins the description of Rust in earnest. The basic data types are discussed, with comments on their acceptable values and ranges. The detail here seems more complete and better arranged than in TRPL and it’s all easy reading. Tuples, arrays, vectors, strings and slices are all introduced here, though not structs or (sadly) enums which are, as in TRPL, left until far too late.
The next couple of chapters discuss ownership (along with moving/taking and borrowing) and references. Lifetimes are introduced here, too, almost incidentally. These are the two ‘difficult’ topics, where Rust’s strictness causes most problems for newcomers, and the treatment here is fairly painless but perhaps underplays their importance. Rust’s smart pointer types
are also discussed here.
Chapter 6 is entitled ‘Expressions’, but is actually an introduction to most of the statement types that are still to be introduced. This is not unreasonable as Rust is an expression-oriented language and most statements can be expressions. Functions are introduced, here, in passing, and there’s enough of an overview of matching to allow
to be covered sensibly.
Chapter 7 deals with error handling. As Rust handles errors using
values that are actually enums, it seems odd to talk about errors before explaining in detail what an enum is. The description here is clear enough, I think, but could have been clearer had the authors simply been able to say ‘
type’ and had the reader already known what an enum was.
Chapter 8 discusses modules in Rust, and introduces Rust’s notion of a crate (or external library). Crates are expected to contain their own tests and documentation, so unit tests and document comments are covered here, too, as are dependencies and the role played by the cargo tool in managing them.
Chapter 9 discusses structs and introduces methods and derived traits. Traits were introduced briefly in the tour in chapter 2, but haven’t been covered in any detail, so the discussion of derived traits really demands a little more explanation than is here, but what is here is clear enough. We also touch here on Rust’s generic types.
Chapter 10 brings the long-awaited discussion of enums and of matching. The discussion of enums is thorough and includes a description of how the compiler arranges enum objects, whose fields may be of different sizes, in memory. The discussion of matching might have given more examples of matching of patterns against enum types … but by now we’ve become so familiar with seeing matches against
types, introduced ahead of time, that there isn’t much new to tell.
Chapter 11 brings a discussion of Rust’s traits, and how they are used to add functionality to types, and to implement generic behaviour. This discussion is carried on in the next couple of chapters in which operator overloading (which depends on traits) and utility traits are discussed. Utility traits include things like
(among others) that are used to add system-defined behaviours to user-defined types so that the compiler can handle them efficiently. Their treatment here is thorough and well-explained.
Chapters follow on closures, iterators, collections, strings and text, and input and output. The last touches on networking while noting that it is beyond the scope of the book. Then comes a chapter on concurrency – one of the longest in the book – which shows how Rust’s type-safety prevents the sharing of mutable data between threads, and shows how communication between threads can nevertheless be safely achieved.
A chapter on macros gives a good overview of writing macros for Rust with a number of practical examples, and finally a chapter on unsafe code brings the book to a close.
PR has some 20% more pages than TRPL, and feels as though it contains about twice as much information with much clearer explanations – though of course it could just be that the material seemed clearer because the subject matter wasn’t all new to me, in which case TRPL must take some of the credit! I was annoyed by a few snide digs at C++ for being less safe than Rust – yes, of course a Rust
is more typesafe than a C
… but you don’t use a C union in C++ you use something like
– those things aside the book is readable and informative. I felt that the ordering of material wasn’t optimal – in particular: Rust’s enum is pervasive and needs to be explained early on – but for the most part the book doesn’t use features that haven’t yet been covered, so there are few surprises. The index isn’t great, but I did find most things that I tried to look up, so it’s better than many.