LazyCell, LazyLock types, checked cfg names and values, exclusive ranges in templates

The Rust team is pleased to announce a new version of the language, 1.80.0. Rust is a programming language that enables everyone to write reliable and efficient software.

If you have a previous version of Rust installed via rustupthen to update to version 1.80.0 you just need to run the command:

$ rustup update stable

If you don't have it installed yet rustupyou can install it with relevant page our website and also see detailed release notes on GitHub.

If you would like to help us test future releases, you can use the beta channel (rustup default beta) or nightly (rustup default nightly). Please, report about all the errors you encountered.

What's Stabilized in 1.80.0

LazyCell And LazyLock

These are “lazy” types that defer initialization of their data until they are first accessed. They are similar to types OnceCell And OnceLock, stabilized at 1.70but with the initialization function included in the type. This completes the stabilization in the standard library of the adapted functionality of popular crates lazy_static And once_cell.

LazyLock — a thread-safe option suitable for places like values static. So, in the example below, the thread that branched off with spawnand the main stream (scope) will see exactly the same duration, because LAZY_TIME will be initialized once, depending on who gets access to the static value first. Neither option requires knowing how exactly initialize it, as in the case of OnceLock::get_or_init.

use std::sync::LazyLock;
use std::time::Instant;

static LAZY_TIME: LazyLock<Instant> = LazyLock::new(Instant::now);

fn main() {
    let start = Instant::now();
    std::thread::scope(|s| {
        s.spawn(|| {
            println!("Thread lazy time is {:?}", LAZY_TIME.duration_since(start));
        });
        println!("Main lazy time is {:?}", LAZY_TIME.duration_since(start));
    });
}

LazyCell does the same thing without thread synchronization, so it doesn't implement Syncnecessary for staticbut it can be used in statics thread_local! (with separate initialization for each thread). Any of these types can be used in other data structures, depending on thread safety needs, so lazy initialization is available everywhere!

Names and values ​​to check cfg

In 1.79 rustc stabilized the flag --check-cfgand now Cargo 1.80 includes these checks for all names it knows cfg (in addition to the built-in rustc). This includes feature names from Cargo.tomland also a new conclusion cargo::rustc-check-cfg from build scripts.

Unexpected configurations are reported by lint unexpected_cfgswhich is designed to detect typos or other errors. For example, in a project with an optional dependency rayon this code is set to the wrong value:

fn main() {
    println!("Hello, world!");

    #[cfg(feature = "crayon")]
    rayon::join(
        || println!("Hello, Thing One!"),
        || println!("Hello, Thing Two!"),
    );
}
warning: unexpected `cfg` condition value: `crayon`
 --> src/main.rs:4:11
  |
4 |     #[cfg(feature = "crayon")]
  |           ^^^^^^^^^^--------
  |                     |
  |                     help: there is a expected value with a similar name: `"rayon"`
  |
  = note: expected values for `feature` are: `rayon`
  = help: consider adding `crayon` as a feature in `Cargo.toml`
  = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
  = note: `#[warn(unexpected_cfgs)]` on by default

This warning is issued regardless of whether the feature is enabled or not. rayon.

Table [lints] V Cargo.toml can also be used to extend the list of known names and values ​​for custom cfg. rustc automatically provides syntax for use in warnings.

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(foo, values("bar"))'] }

You can read more about this functionality in the previous blog articleannouncing this functionality in nightly.

Exclusive ranges in templates

Rust range templates can now use end-exclusive ranges, written as a..b or ..bsimilar to expression types Range And RangeTo. For example, the following templates can now use the same constants to end one template and begin the next:

pub fn size_prefix(n: u32) -> &'static str {
    const K: u32 = 10u32.pow(3);
    const M: u32 = 10u32.pow(6);
    const G: u32 = 10u32.pow(9);
    match n {
        ..K => "",
        K..M => "k",
        M..G => "M",
        G.. => "G",
    }
}

Previously, only ranges that included the endpoint (called “inclusive”) were allowed in templates. a..=b or ..=b), or open (a..) ranges. So code like the one above required entering separate constants, such as K - 1 for end points.

Exclusive ranges have been around as an unstable feature for a while now, but stabilization has been hampered by concerns that they could introduce confusion and increase the likelihood of errors in patterns. As a result, exhaustive pattern matching checks have been improved to better detect gaps in the match, and new lints non_contiguous_range_endpoints And overlapping_range_endpoints will help you identify cases where you would like to change exclusive range templates to inclusive ones or vice versa.

Stabilized APIs

The following APIs can now be used in context const:

Other changes

Check everything that has changed in Rust, Cargo And Clippy.

Who worked on 1.80.0

Many people came together to create Rust 1.80.0. We couldn't have done it without you. Thank you!

From the translators

If you have any questions about the Rust language, you can get help at Russian-language Telegram chat or in a similar way chat for newbie questions. If you have any questions about translations or want to help with them, please contact translator chat.

This article was translated jointly by andreevlex, TelegaOvoshey and funkill.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *