The Rust development team is pleased to announce the release of a new version of Rust, 1.32.0. Rust is a programming language that allows everyone to create reliable and efficient software.
If you have a previous version of Rust installed using rustup
, then to update Rust to version 1.32.0, you just need to run:
$ rustup update stable
If you have not yet installed rustup
, you can install it from the corresponding page of our website. Detailed notes for the release of Rust 1.32.0 can be found on GitHub.
Arustup
note: there have been several new releases ofrustup
! To updaterustup
itself, perform arustup self update
.
Rust 1.32.0 acquired several life-enhancing improvements, changed the default memory allocator and made more functions constant. Read about these changes below or see the release notes for details.
Let's start with a life-enhancing improvement. Are you using "print debugging"? If yes, and you want to print some value in the process of working on the code, you have to do this:
let x = 5; println!("{:?}", x); // или даже так println!("{:#?}", x);
This is not the biggest obstacle that slows down development, but it takes too much effort to easily debug output x
values. In addition, the context is not taken into account. If you have several such println!
Now, it becomes difficult to determine what is related to the output until you yourself add context information to each call, which requires even more work.
For these purposes, in Rust 1.32.0 we added a new dbg macro! :
fn main() { let x = 5; dbg!(x); }
After starting this program, you will see:
[src/main.rs:4] x = 5
Together with the variable name and its value, the file name and the line number where the dbg!
call was made will be displayed dbg!
.
Also println!
prints to standard output, so it's best to use eprintln!
for printing standard error. Macro dbg!
prints to stderr
, and rightly so.
This works even in difficult cases. Consider an example of factorial implementation:
fn factorial(n: u32) -> u32 { if n <= 1 { n } else { n * factorial(n - 1) } }
In order to debug it, we can use eprintln!
:
fn factorial(n: u32) -> u32 { eprintln!("n: {}", n); if n <= 1 { eprintln!("n <= 1"); n } else { let n = n * factorial(n - 1); eprintln!("n: {}", n); n } }
We want to output n
at each iteration and see the context of each of the branches. For factorial(4)
following will be displayed:
n: 4 n: 3 n: 2 n: 1 n <= 1 n: 2 n: 6 n: 24
This is acceptable, but not particularly good. Perhaps we could work on improving the display of context information to make the conclusion clearer. But then, instead of debugging your code, we’ll work on improving the debugging code.
Consider the same example using dbg!
:
fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { dbg!(1) } else { dbg!(n * factorial(n - 1)) } }
We simply wrapped a macro with each of the expressions we want to output. As a result, we get:
[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
Since the dbg!
macro dbg!
returns the debugged value itself, unlike eprintln!
, which returns ()
, we do not need to make any changes in the structure of our code. Additionally, we get a much more useful conclusion.
We paid a lot of attention to such a small macro, since we hope that it will simplify your debugging process. Of course, we are also continuing to work on supporting gdb
and co.
jemalloc
removed by jemalloc
A long time ago, Rust had a big runtime, similar to Erlang. For him, jemalloc was chosen instead of the system allocator, because it was often more productive. Gradually, we got rid of the runtime more and more, and in the end it was almost all removed, but the jemalloc remained. We had no way to choose a user allocator, and therefore we could not completely remove jemalloc so as not to harm those who needed it.
In addition, the claim that jemalloc
was always the default jemalloc
was primarily for the UNIX world, since it was by default only on some platforms. In particular, the goal of MSVC on Windows has long been using the system allocator.
Finally, although jemalloc usually has good performance, this is not always the case. In addition, it adds about 300 kilobytes to each executable file. We also have a lot of other problems with jemalloc. And in general, it is strange that the default system language does not use the system allocator.
For these reasons, as soon as Rust 1.28 provided a way to select a global allocator , we began to plan the transition to the default system allocator and the provision of jemalloc
as an external library. In Rust 1.32, we have finally completed this work, and now by default your program will use the system allocator.
If you want to continue using jemalloc, use the jemallocator library . To do this, in Cargo.toml
specify:
jemallocator = "0.1.8"
And in the root file of your project:
#[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
That's all! If you don't need jemalloc, you are no longer forced to use it, but if you need it, then the problem is solved with a few lines of code.
In the last two issues, we talked about several improvements to the module system. In 1.32.0 and edition 2018, we added the latest change. It is called "uniform paths" and allows you to work with import paths in the same way as with other paths that did not work correctly before. For example:
enum Color { Red, Green, Blue } use Color::*;
This code has not been compiled before , since the paths in use
must have started with super
, self
or crate
. Now, thanks to the compiler support for uniform paths, this code will work and do what you expect: importing the variants of the Color
enumeration defined above.
This change completes our revision of the module system. We hope you enjoy working with the simplified system!
Rust 1.32.0 released several macro enhancements. First, a new literal fragment specifier was added:
macro_rules! m { ($lt:literal) => {}; } fn main() { m!("some string literal"); }
The literal
fragment is associated with literals of any type: string, numeric, and character.
In the 2018 edition, macro_rules
can also be used in the macro ?
:
macro_rules! bar { ($(a)?) => {} }
Fragment with ?
a zero or one occurrence will be matched, just as a fragment with a *
already associates a "zero or more" occurrences, and a +
- a "one or more" occurrences.
Macro dbg!
, which we have already described above, has become an important addition to the standard library. In addition, 19 functions were made constant, and all numerical primitive types received conversion functions into a byte array and back with the specified byte order. There are six functions with the names to_<endian>_bytes
and from_<endian>_bytes
, where <endian>
is:
ne
- native endiannessle
- order from junior to senior (little endian)be
- order from older to younger (big endian)See the release notes for details.
Cargo has been given the cargo c alias for the cargo check team , and now allows using usernames in repository URLs .
See the release notes for details.
Many people co-created Rust 1.32.0. We could not complete the work without the participation of each of you. Thank!
From the translator: I express special thanks to the members of the Rustycrate community and personally @dashadee and ozkriff for their help with translation and proofreading.
Source: https://habr.com/ru/post/436854/