Rust 1.32 includes a number of new language features meant to improve developer experience when tracing the execution of programs for debugging purposes. Additionally, Rust now uses the system allocator by default for memory allocation, and this release also completes work on the module system which make it easier to use, and more.
The new dbg!
macro greatly streamlines the task of printing out debug information. For example, if you want to print the value of a variable x
, you can now just use dbg!(x);
instead of the cumbersome println!("{:#?}", x);
. As a bonus, dbg!
will also automatically print file and line number and the name of the variable being dumped. Another great feature of dbg!
is it is a function that returns the value being printed out, which enables its use within expressions, like in the following case:
fn factorial(n: u32) -> u32 {
if dbg!(n <= 1) {
dbg!(1)
} else {
dbg!(n * factorial(n - 1))
}
}
The code above produces the following verbose output which makes it very easy to follow each step of the recursion:
[src/main.rs:3] n <= 1 = false
[src/main.rs:3] n <= 1 = false
[src/main.rs:3] n <= 1 = false
[src/main.rs:3] n <= 1 = true
[src/main.rs:4] 1 = 1
[src/main.rs:5] n * factorial(n - 1) = 2
[src/main.rs:5] n * factorial(n - 1) = 6
[src/main.rs:5] n * factorial(n - 1) = 24
[src/main.rs:11] factorial(4) = 24
InfoQ already covered module improvements Rust 1.31 introduced to make module usage more straightforward, including better module path resolution leading to simplified module syntax. Rust 1.32 goes a step further with uniform paths, which enable the use
of non-import paths by relaxing the requirement that use
declarations must be followed by crate
, self
, or super
. This is exemplified in the following example:
enum Color { Red, Green, Blue }
use Color::*;
As mentioned, Rust 1.32 also improves its macro system by introducing a literal
pattern matcher and enabling the use of ?
. For example, the following two macros define each a single rule that will be selected for expansion when the provided token list matches respectively a literal or zero or more repetition of a given pattern:
macro_rules! m1 {
($lt:literal) => {};
}
macro_rules! m2 {
($(a)?) => {}
}
Last but not least, Rust 1.32 finally sets things straight with the memory allocator by defaulting to use the system allocator and making the old default allocator, jemalloc
, opt-in. Until Rust 1.28, the only allocator available wasjemalloc
, whose origins trace back to the times when Rust had its own Erlang-like runtime. Now, that runtime was quite large and the Rust team went on progressively reducing it to a kind of minimalist runtime like those found in languages like C and C++. One of the last remnants of the old runtime was jemalloc
, which was still exacting about 300KB from every Rust binary. Hence the decision to make it first opt-out in Rust 1.28 and now opt-in with Rust 1.32 for all those cases where it provides a performance edge.
If you are interested in Rust latest features, do not miss the official release notes to get the full detail.