The Rust team is pleased to present the release of Rust 1.16.0. Rust is a system programming language aimed at security, speed, and parallel code execution.
If you have a previous version of Rust installed, then it’s enough to upgrade:
$ rustup update stable
If you have not yet installed Rust, then you can rustup
from the corresponding page of our website and read the detailed release notes for 1.16.0 on GitHub.
The biggest addition to Rust 1.16 is the cargo check
team. This new subcommand in most cases should speed up the development process.
What she does? Let's go back a bit and talk about how rustc
compiles your code. Compilation takes place in several "passes". This means that the compiler performs many different steps before a binary file is created from your source code. You can see each of these stages (and how much time and memory they take) by passing the -Z time-passes
parameter to the compiler (only for nightly):
rustc .\hello.rs -Z time-passes time: 0.003; rss: 16MB parsing time: 0.000; rss: 16MB recursion limit time: 0.000; rss: 16MB crate injection time: 0.000; rss: 16MB plugin loading time: 0.000; rss: 16MB plugin registration time: 0.049; rss: 34MB expansion <snip>
A lot of them. However, you can divide them into two big steps. First, rustc
performs all security checks and syntax correctness. Second: after making sure that everything is in order, it will create a binary file, which you will eventually run.
As you can see, the second stage takes a lot of time. And in most cases it is not necessary. Many developers work on Rust projects like this:
cargo build
to make sure it compiles.cargo test
to make sure that the tests run successfully.In the second step, you never run your code. You are only interested in messages from the compiler. cargo check
solves this particular problem: it runs all compiler checks, but does not create a binary file.
So what kind of acceleration do you actually get? As with most performance issues, the answer is "when, how." Here are some very unscientific tests:
initial assembly | initial check | acceleration | reassembly | retest | acceleration | |
---|---|---|---|---|---|---|
thanks | 134.75s | 50.88s | 2.648 | 15.97s | 2.9s | 5.506 |
cargo | 236.78s | 148.52s | 1.594 | 64.34s | 9.29s | 6.925 |
diesel | 15.27s | 12.81s | 0.015 | 13.54s | 12.3s | 1.100 |
The 'initial' category is the first build after a project was cloned. For the category 'repeated', one empty line was added to the beginning of the src\lib.rs
, after which the command was executed again. That is why the initial build looks more sad; besides the project itself, the command is executed for all its dependencies. As you can see, a large project with a lot of dependencies will see noticeable improvements, but for small ones there is almost no difference.
We are also still working on improving the compilation time as a whole, although now we cannot boast of anything concrete.
To support cargo check
, rustc
learned to generate a new kind of file: .rmeta
. This file contains only metadata about a particular container. cargo check
uses this for your dependencies so that the compiler can check types and the like. This is also useful for the Rust Language Server and possibly other tools that will appear later.
Another important change is the removal of a long-time diagnostic: consider using an explicit lifetime parameter
. This diagnostic worked every time you had an incorrect annotation of the lifetime, and the compiler thinks you meant something else. Consider the following code:
use std::str::FromStr; pub struct Name<'a> { name: &'a str, } impl<'a> FromStr for Name<'a> { type Err = (); fn from_str(s: &str) -> Result<Name, ()> { Ok(Name { name: s }) } }
Here Rust is not sure what to do with the lifetime; This code does not guarantee that s
will live as long as Name
. In this case, s
necessary for the Name
be valid. Let's try to compile this code in Rust 1.15.1:
> rustc +1.15.1 foo.rs --crate-type=lib error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements --> .\foo.rs:10:5 | 10 | fn from_str(s: &str) -> Result<Name, ()> { | _____^ starting here... 11 | | Ok(Name { name: s }) 12 | | } | |_____^ ...ending here | help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name, ()> --> .\foo.rs:10:5 | 10 | fn from_str(s: &str) -> Result<Name, ()> { | _____^ starting here... 11 | | Ok(Name { name: s }) 12 | | } | |_____^ ...ending here
The compiler explains the problem and gives useful advice. Well, let's try to use it. Modify the code by adding 'a
, and try compiling again.
> rustc +1.15.1 .\foo.rs --crate-type=lib error[E0308]: method not compatible with trait --> .\foo.rs:10:5 | 10 | fn from_str(s: &'a str) -> Result<Name, ()> { | _____^ starting here... 11 | | Ok(Name { name: s }) 12 | | } | |_____^ ...ending here: lifetime mismatch | <snip> help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name<'a>, ()> --> .\foo.rs:10:5 | 10 | fn from_str(s: &'a str) -> Result<Name, ()> { | _____^ starting here... 11 | | Ok(Name { name: s }) 12 | | } | |_____^ ...ending here
It still does not work. The advice was not that helpful. Now he suggests adding another lifetime, this time for Name
. If we do this ...
> rustc +1.15.1 .\foo.rs --crate-type=lib <snip> help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name<'a>, ()> --> .\foo.rs:10:5
... I've already watched this movie ... Compiler ?!
This diagnosis had good intentions, but, as can be seen from this example, when she was wrong, she was wrong very much . Sometimes she even suggested incorrect syntax for Rust! Moreover, the more experienced programmers at Rust do not really need this hint, but beginners took them on faith, and went into the wilds. Because of this, we decided to completely remove this message . Perhaps we will return it in the future, but only if we can limit the false positives.
Of the other diagnostic changes, the previous version of Rust tried to suggest corrections for typos:
let foo = 5; println!("{}", ffo);
The code above caused the following error:
error[E0425]: cannot find value `ffo` in this scope --> foo.rs:4:20 | 4 | println!("{}", ffo); | ^^^ did you mean `foo`?
However, this could happen only in certain circumstances: sometimes for local variables and for structure fields. Now it works almost everywhere . In combination with some other relevant improvements, this leads to a significant improvement in these types of diagnostics.
See the release notes for details.
21 new interfaces have been stabilized:
VecDeque::truncate
VecDeque::resize
String::insert_str
String::split_off
Duration::checked_add
Duration::checked_sub
Duration::checked_div
Duration::checked_mul
str::replacen
str::repeat
SocketAddr::is_ipv4
SocketAddr::is_ipv6
IpAddr::is_ipv4
IpAddr::is_ipv6
Vec::dedup_by
Vec::dedup_by_key
Result::unwrap_or_default
<*const T>::wrapping_offset
<*mut T>::wrapping_offset
CommandExt::creation_flags
File::set_permissions
In addition, a number of minor improvements were made to existing functions. For example, writeln!
, just like println!
, can now take one argument . As a result, he writes only a newline character, but this is a beautiful symmetry.
Now all structures in the standard library Debug
.
Improved error message when getting a &str
slice. For example, for this code:
&"abcαβγ"[..4]
The following error will be displayed:
thread 'str::test_slice_fail_boundary_1' panicked at 'byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of `abcαβγ`'
Parts after ;
was not there before.
See the release notes for details.
In addition to cargo check
, Cargo and crates.io have several new features. For example, cargo build
and cargo doc
now accept the - all flag to build and document all containers in your workspace.
Cargo now has a --version --verbose
flag, similar to rustc
.
Crates.io can now display TravisCI or AppVeyor icons for your container.
Both Cargo and crates.io now understand the categories . Unlike keywords that can be specified in free form, categories are supervised. Keywords, unlike categories, are used for search. In other words, categories are meant to help you browse the catalog, and keywords are meant to be searched.
You can browse containers by category here .
See the release notes for details.
In the last issue, we introduced thanks.rust-lang.org . We do some refactoring to add other projects besides Rust itself. We hope to introduce this in the next issue.
137 people contributed to Rust 1.16. Thank!
Translated by Sergey Veselkov
Source: https://habr.com/ru/post/324448/