Updates in Rust 2021 edition

Reading Time: 2 minutes

The new edition of Rust is here. The edition 2021 of Rust have many interesting changes in it. Let us have a look at some of the changes in edition 2021.

Additions to the prelude

  • The TryIntoTryFrom and FromIterator traits are now part of the prelude.
  • This might make calls to trait methods ambiguous which could make some code fail to compile.

However, adding a trait to the prelude can break existing code in a subtle way. For example, a call to x.try_into() which comes from a MyTryInto trait might fail to compile if std‘s TryInto is also imported, because the call to try_into is now ambiguous and could come from either trait. This is the reason, edition 2021 has not added TryInto to the prelude yet, since there is a lot of code that would break this way.

As a solution, Rust 2021 will use a new prelude. It’s identical to the current one, except for three new additions:

  • std::convert::TryInto
  • std::convert::TryFrom
  • std::iter::FromIterator

Disjoint capture in closures

  • || a.x + 1 now captures only a.x instead of a.
  • This can cause things to be dropped at different times or affect whether closures implement traits like Send or Clone.
    • If possible changes are present, cargo fix will insert statements like let _ = &a to force a closure to capture the entire variable.

Panic macro consistency

  • panic!(..) now always uses format_args!(..), just like println!().
  • panic!("{") is no longer , without escaping the { as {{.
  • panic!(x) is no longer accepted if x is not a string literal.
    • Use std::panic::panic_any(x) to panic with a non-string payload.
    • Or use panic!("{}", x) to use x‘s Display implementation.
  • The same applies to assert!(expr, ..).

Reserving syntax

  • any_identifier#any_identifier"...", and any_identifier'...' are now reserved syntax, and no longer tokenize.
  • This is mostly relevant to macros. E.g. quote!{ #a#b } is no longer accepted.
  • It doesn’t treat keywords specially, so e.g. match"..." {} is no longer accepted.
  • Insert whitespace between the identifier and the subsequent #", or ' to avoid errors.
  • Edition migrations will help you insert whitespace in such cases.

To make space for new syntax in the future, we’ve decided to reserve syntax for prefixed identifiers and literals: prefix#identifierprefix"string"prefix'c', and prefix#123, where prefix can be any identifier. (Except those prefixes that already have a meaning, such as b'...' (byte strings) and r"..." (raw strings).)

Or patterns in macro-rules

  • How patterns work in macro_rules macros changes slightly:
    • $_:pat in macro_rules now matches usage of | too: e.g. A | B.
    • The new $_:pat_param behaves like $_:pat did before; it does not match (top level) |.
    • $_:pat_param is available in all editions.

This edition has extended Patterns to support | nested anywhere in the pattern. This enables you to write Some(1 | 2) instead of Some(1) | Some(2).

IntoIterator for arrays

  • Arrays implement IntoIterator in all editions.
  • Calls to IntoIterator::into_iter are hidden in Rust 2015 and Rust 2018 when using method call syntax (i.e., array.into_iter()). So, array.into_iter() still resolves to (&array).into_iter() as it has before.
  • array.into_iter() changes meaning to be the call to IntoIterator::into_iter in Rust 2021.

Default Cargo feature resolver

edition = "2021" implies resolver = "2" in Cargo.toml.

Warnings promoted to errors

Code that triggered the bare_trait_objects and ellipsis_inclusive_range_patterns lints will error in Rust 2021. These two existing lints are becoming hard errors in Rust 2021, but these lints will remain warnings in older editions.

If you want to read more content like this?  Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.