📜 ⬆️ ⬇️

Rust 1.30 release

The Rust development team is pleased to announce the release of a new version of Rust: 1.30.0. Rust is a system programming language aimed at security, speed, and parallel code execution.


If you have a previous version of Rust installed using rustup , then to update Rust to version 1.30.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.30.0 can be found on GitHub.


What is included in the stable version 1.30.0


Rust 1.30 is an outstanding release with a number of important innovations. But on Monday, the official blog will be published, please check the beta version of Rust 1.31, which will be the first release of "Rust 2018". For more information about this, see our previous publication "What is Rust 2018" .


Procedural macros


Back in Rust 1.15, we added the ability to define "custom derive macros". For example, using serde_derive , you can declare:


 #[derive(Serialize, Deserialize, Debug)] struct Pet { name: String, } 

And convert Pet to JSON and back to structure using serde_json . This is possible thanks to the automatic Deserialize Serialize and Deserialize types using procedural macros in serde_derive .


Rust 1.30 expands the functionality of procedural macros by adding the ability to define two other types of macros: "attribute procedural macros" and "functional procedural macros".


Attribute macros are similar to derive macros for automatic output, but instead of generating code only for the #[derive] attribute, they allow users to create their own new attributes. This makes them more flexible: derive macros only work for structures and enums, but attributes can be applied to other objects, such as functions. For example, attribute macros allow you to do the following when using a web framework:


 #[route(GET, "/")] fn index() { 

This #[route] attribute will be defined in the framework itself as a procedural macro. Its signature will look like this:


 #[proc_macro_attribute] pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream { 

Here we have two input parameters of the TokenStream type: the first is for the content of the attribute itself, that is, these are the GET, "/" parameters. The second is the body of the object to which the attribute is applied. In our case, this is fn index() {} and the rest of the function body.


Functional macros define such macros, the use of which looks like a function call. For example, the macro sql! :


 let sql = sql!(SELECT * FROM posts WHERE id=1); 

Inside this macro, it will parse SQL expressions and check them for syntactic correctness. A similar macro should be declared as follows:


 #[proc_macro] pub fn sql(input: TokenStream) -> TokenStream { 

This is similar to the derive macro signature: we get the tokens that are inside the parentheses, and return the code generated from them.


Macros and use


You can now import macros into scope using the use keyword . For example, to use the json macro from the serde-json package, the entry used was:


 #[macro_use] extern crate serde_json; let john = json!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] }); 

And now you will have to write:


 extern crate serde_json; use serde_json::json; let john = json!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] }); 

Here, the macro is imported as well as other elements, so there is no need to use the macro_use annotation.


Finally, the proc_macro package is stabilized , which provides the API needed for writing procedural macros. It also significantly improved the error handling API, and packages like syn and quote already using it. For example, before:


 #[derive(Serialize)] struct Demo { ok: String, bad: std::thread::Thread, } 

led to this error:


 error[E0277]: the trait bound `std::thread::Thread: _IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not satisfied --> src/main.rs:3:10 | 3 | #[derive(Serialize)] | ^^^^^^^^^ the trait `_IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not implemented for `std::thread::Thread` 

Now it will be issued:


 error[E0277]: the trait bound `std::thread::Thread: serde::Serialize` is not satisfied --> src/main.rs:7:5 | 7 | bad: std::thread::Thread, | ^^^ the trait `serde::Serialize` is not implemented for `std::thread::Thread` 

Improving the system of modules


The module system has long become a sore spot for newcomers to Rust; some of its rules were inconvenient in practice. These changes are the first step we take to simplify the system of modules.


In addition to the above change for macros, there are two new improvements in the use of use . First, external packages are now added to the prelude , that is:


 //  let json = ::serde_json::from_str("..."); //  let json = serde_json::from_str("..."); 

The catch is that the old style was not always needed because of the peculiarities of the Rust modules system:


 extern crate serde_json; fn main() { //   ;     ,  `serde_json` //     let json = serde_json::from_str("..."); } mod foo { fn bar() { //   ;     `foo`,  `serde_json` //    let json = serde_json::from_str("..."); } //   -        `use` use serde_json; fn baz() { //   -   `::serde_json`,   //  ,   let json = ::serde_json::from_str("..."); } } 

It was unpleasant to get broken code just by moving the function to a submodule. Now the first part of the path will be checked, and if it corresponds to some extern crate , then it will be used regardless of the position of the call in the hierarchy of modules.


Finally, use began to support the import of elements into the current scope with paths that begin with crate :


 mod foo { pub fn bar() { // ... } } //  use ::foo::bar; //  use foo::bar; //  use crate::foo::bar; 

The crate keyword at the beginning of the path indicates that the path will start from the root of the package. Previously, the paths specified in the use import line were always indicated relative to the package root, but the paths in the rest of the code that directly refer to elements were indicated relative to the current module, which led to contradictory behavior of the paths:


 mod foo { pub fn bar() { // ... } } mod baz { pub fn qux() { //  ::foo::bar(); //  ,    `use`: // foo::bar(); //  crate::foo::bar(); } } 

As soon as the new style becomes widely used, it will hopefully make the absolute paths more clear without needing to use the ugly prefix :: .


All these changes combine to make it easier to understand how paths are resolved. In any place where you see the path a::b::c , besides the use statement, you can ask:



The old behavior of paths in use , always starting from the root of the package, is still applicable. But in the case of a one-time transition to a new style, these rules will be applied to paths everywhere uniformly, and you will have to take much less care of imports when moving the code.


Raw ids


You can now use keywords as identifiers using the following new syntax:


 //      `for` let r#for = true; //     `for` fn r#for() { // ... } //    r#for(); 

There are not many cases when it will be useful to you. But once you try to use the package for Rust 2015 in the project for Rust 2018 or vice versa, then the set of keywords will be different. We will tell about it in more detail in the upcoming announcement of Rust 2018.


Applications without a standard library


Back in Rust 1.6, we announced stabilization of "no_std" and libcore for creating projects without a standard library. However, with one clarification: it was possible to create only libraries, but not applications.


In Rust 1.30, you can use the attribute #[panic_handler] for self-realization of panic. This means that you can now create applications, not just libraries that do not use the standard library.


Other


One last thing: in macros, you can now map scope modifiers , such as pub , using the vis specifier. Additionally, "instrumental attributes", such as #[rustfmt::skip] , are now stabilized . True for use with static analysis tools like #[allow(clippy::something)] , they are not yet stable.


See the release notes for details.


Standard Library Stabilization


The following APIs have been stabilized in this release:



In addition, the standard library has long had functions for removing spaces on one side of some text, such as trim_left . However, for RTL languages, the meaning of "right" and "left" here leads to confusion. Therefore, we introduce new names for these functions:



We plan to declare obsolete the old names (but not delete, of course) in Rust 1.33.


See the release notes for details.


Improvements in Cargo


Cargo's biggest improvement in this release is that we now have a progress bar!


demo gif


See the release notes for details.


Developers 1.30.0


Many people co-created Rust 1.30. 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 vitvakatu and Virtuos86 for their help with translation and proofreading.


')

Source: https://habr.com/ru/post/428073/


All Articles