

Rust 1.30 Brings More Metaprogramming Support and Improved Modules
source link: https://www.tuicool.com/articles/hit/JnQBZrI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The latest release of Rust, version 1.30, extends procedural macros by allowing them to define new attributes and function-like macros. Additionally, it streamlines Rust module system by making it more consistent and straightforward.
Rust 1.30 introduces two new types of procedural macros , “attribute-like procedural macros” and “function-like procedural macros”. Procedural macros are Rust metaprogramming foundation and enable the manipulation of a program syntax tree. In this respect, procedural macros are much more powerful than declarative macros , that provide a mechanism to define a shorthand for more complex code based on pattern matching.
Attribute-like procedural macros are similar to existing derive macros but are more flexible in that they allow you to create new attributes and may be applied also to functions in addition to structs and enums. For example, an attribute macro could enable the specification of a route
attribute to define HTTP routing:
// use of route procedural macro #[route(GET, "/")] fn index() { ... } // procedural macro defining route #[proc_macro_attribute] pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream { // attr receives the GET, "/" part of the macro // item receives fn index () { ... }
Similarly, function-like procedural macros allows you to define macros that look like functions, e.g.:
// parse an SQL statement let sql = sql!(SELECT * FROM posts WHERE id=1); #[proc_macro] pub fn sql(input: TokenStream) -> TokenStream {
In both examples, TokenStream
represents the syntax tree the attribute is applied to or the attribute/function definition. The route
/ sql
function converts the received syntax tree into a new syntax tree which is returned to the caller, i.e., generating new code to execute
.
Rust 1.30 also brings a few changes to the use
macro to improve developer experience when using Rust module system. Firstly, use
can now bring in a macro definition, thus making the macro_use
annotation obsolete:
// old: #[macro_use] extern crate serde_json; // new: extern crate serde_json; use serde_json::json;
Additionally, external crates are now more resilient to functions being moved across the module hierarchy by ensuring all references to a namespace are checked against all extern crate
directives included in the module prelude and using the one that matches, if any. Previously, you had to explicitly use extern
inside of a module or use the ::extern_name
syntax, as shown in the following example:
extern crate serde_json; fn main() { let json = serde_json::from_str("..."); // OK } mod foo { // to use serde_json in this module you explicitly use it use serde_json; fn bar() { let json = serde_json::from_str("..."); } fn baz() { // alternatively, you fully qualify the external module name let json = ::serde_json::from_str("..."); }
Finally, use
is now more consistent in the way it interprets module paths. You can use now the crate
keyword to indicate that you would like the module path to start at your crate root. Previous to 1.30, this was the default for module paths but paths referring to items directly would start at the local path:
mod foo { pub fn bar() { // ... } } mod baz { pub fn qux() { // old ::foo::bar(); // does not work, which is different than with `use`: // foo::bar(); // new crate::foo::bar(); } }
More changes brought by Rust 1.30 are the following:
-
You can now use keywords as identifiers by prefixing them with
r#
, e.g.r#for
. This change is mostly motivated by the fact that Rust 2018 will introduce new keywords, so a mechanism shall be available to convert existing code using those keywords as variable or function names. -
It is now possible to build applications not using the standard library with
no_std
. Previously, you could only build libraries withno_std
due to the impossibility of defining a panic handler .
You can update your Rust distribution using $ rustup update stable
. For full detail of Rust 1.30 do not miss the release notes
.
Recommend
-
54
Metaprogramming: Ruby Hook Methods Ruby comes with a bunch of hook methods that allow you...
-
33
In Karumi over the last few months we have been trying to generate a Sourcery template that would help us to automate the composition root file we usually have to deal with all the dependencies generation ceremony, but du...
-
46
What is Manifold? Manifold re-energizes Java with powerful features like Type-safe M...
-
21
README.md
-
24
The art of metaprogramming, Part 1 Introduction to metaprogramming Write programs to generate other programs Jonathan Bartlett Published on October 20, 2005 ...
-
33
In some domains of programming it’s common to want to write a data structure or algorithm that can work with elements of many different types, such as a generic list or a sorting algorithm that only needs a comparison fu...
-
44
It's hard to avoid using Devise in a Rails project. That's mostly because the ease of using it is hard to beat. Devise is incredibly configurable and that often means having code that can be hard to follow. Providi...
-
15
in which metaprogramming crosses several runtime boundaries Since the deprecation of swank-clojure I've been a happy user of
-
12
Let's Learn x86-64 Assembly! Part 1 - Metaprogramming in Flat Assembler This post is a part of a series on...
-
5
Build Throughput Series: More Efficient Template MetaprogrammingXiangJan...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK