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 rustup
then 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 rustup
you 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 spawn
and 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 Sync
necessary for static
but 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-cfg
and 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.toml
and also a new conclusion cargo::rustc-check-cfg
from build scripts.
Unexpected configurations are reported by lint unexpected_cfgs
which 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 ..b
similar 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.