Rust 1.95.0 Released: Key Features and Changes
Rust 1.95.0 introduces cfg_select!, if-let guards in match, atomic update methods, new collection functions, and many stabilized APIs. Update via rustup.
Welcome to the Rust 1.95.0 release! This version brings several new features, including a compile-time configuration macro, enhanced pattern matching in match expressions, and a host of stabilized APIs. Whether you are a seasoned Rustacean or just getting started, these updates aim to make your coding experience more efficient and expressive. Below we answer common questions about what's new in this release.
What is the new cfg_select! macro and how does it work?
The cfg_select! macro, stabilized in Rust 1.95.0, acts like a compile-time match on configuration predicates. It evaluates the first arm whose cfg condition is true and expands to the corresponding right-hand side. This serves a similar purpose to the popular cfg-if crate but with its own syntax. For example, you can write:

cfg_select! {
unix => { fn foo() { /* unix specific */ } }
target_pointer_width = "32" => { fn foo() { /* 32-bit fallback */ } }
_ => { fn foo() { /* general fallback */ } }
}
The macro can also be used in expression context, such as returning a string based on the target OS. This feature simplifies conditional compilation without needing external dependencies.
How do if‑let guards enhance match expressions?
Rust 1.95.0 extends the capability of let chains into match arms via if‑let guards. Previously, you could use if guards, but now you can combine pattern matching with if let inside a match arm. For instance:
match value {
Some(x) if let Ok(y) = compute(x) => {
println!("{}, {}", x, y);
}
_ => {}
}
This allows you to bind additional variables from a fallible operation within the same arm. Note that, like regular if guards, the compiler does not consider if‑let guards when checking exhaustiveness of the match. This feature makes pattern matching more expressive and reduces the need for nested matches.
What new atomic operations are stabilized?
Rust 1.95.0 stabilizes several atomic methods for easier concurrent programming. The AtomicBool, AtomicPtr, and AtomicIn/AtomicUn (signed/unsigned integer atomics) all gain update and try_update methods. These functions atomically read the current value, apply a closure, and attempt to store the new value using a compare-and-exchange loop. update retries until success, while try_update returns an Err if the value has changed concurrently. This provides a convenient, lock‑free way to modify atomic variables without manual CAS loops.
What new methods for Vec and other collections are added?
The standard library now includes push_mut, insert_mut, and similar methods for several collections. Vec::push_mut and Vec::insert_mut allow you to push or insert a value and get a mutable reference to the newly added element. These methods are also added to VecDeque (push_front_mut, push_back_mut, insert_mut) and LinkedList (push_front_mut). This is especially useful when you need to modify the element immediately after insertion without needing an index lookup. The exact signatures are available in the standard library documentation.
How can I update to Rust 1.95.0?
If you already have Rust installed via rustup, updating to version 1.95.0 is straightforward. Run the following command in your terminal:
rustup update stable
This will fetch the latest stable release (1.95.0) and set it as your default toolchain. If you don't have rustup yet, you can obtain it from the official Rust website. For those who want to test upcoming features, you can switch to the beta or nightly channels using:
rustup default beta
rustup default nightly
Any bugs encountered can be reported on the Rust issue tracker.
What core library additions are included?
Rust 1.95.0 stabilizes a number of core APIs. Notably, MaybeUninit<[T; N]> now implements several conversion traits like From<[MaybeUninit<T>; N]> and AsRef/AsMut for slices. Similarly, Cell<[T; N]> gains AsRef implementations. The bool type now implements TryFrom<{integer}>, allowing safe conversion from integers (where 0 is false and 1 is true, returning an error otherwise). A new module core::range introduces RangeInclusive and RangeInclusiveIter. The core::hint::cold_path function is stabilized, which hints to the optimizer that a code path is unlikely. Additionally, *const T and *mut T gain as_ref_unchecked and as_mut_unchecked methods for unsafe conversion to references.