What Is New in Rust 1.58
| Category | Highlights |
|---|---|
| New Features | Captured identifiers in format strings; Windows Command search path no longer includes the current directory. |
| Improvements | Expanded #[must_use] annotations across the standard library; several std APIs stabilized as const; other library stabilizations. |
How can I use captured identifiers directly in Rust format strings?
You can write {ident} inside a format string and the compiler will capture a local variable with that name.
This works for any macro that accepts a format string, such as println!, format!, or panic! (in the 2021 edition).
let person = get_person();\nprintln!("Hello, {person}!"); // captures the local `person`\n\nlet (width, precision) = get_format();\nfor (name, score) in get_scores() {\n println!("{name}: {score:width$.precision$}");\n}
Only plain identifiers are allowed; complex expressions must be bound to a name first or use the older name = expr syntax.
Why does std::process::Command no longer search the current directory on Windows?
Rust removed the current-directory lookup to avoid accidental or malicious executable hijacking.
Historically the win32 CreateProcess API caused Rust to search the parent's current directory after the child's PATH. This could let an attacker place a rogue binary in a writable directory and have it executed unintentionally.
The new search order on Windows is:
- The child's
PATHenvironment variable. - The directory from which the application loaded.
- The 32-bit Windows system directory.
- The Windows directory.
- The parent's
PATHenvironment variable.
Non-Windows platforms keep their existing behavior.
What new #[must_use] annotations were added in Rust 1.58 and how do they affect my code?
Rust 1.58 expands #[must_use] across many more standard-library functions and types, so ignoring their return values now triggers a compiler warning.
This helps catch bugs where a function's primary effect is its return value, such as error-handling or builder-style APIs.
- Various iterator adapters now carry #[must_use] because they produce a new iterator.
- Methods that allocate or transform collections (e.g.,
Vec::pushstill returns(), butVec::appendnow warns if the result is ignored). - Result-producing functions in
std::fsandstd::netare marked #[must_use].
In practice, most teams will see new warnings during CI builds and should add explicit handling or discard the value with let _ = ...; if the result is truly irrelevant.
Which standard library APIs became const in Rust 1.58?
A handful of previously stable functions were upgraded to const, allowing them to be evaluated at compile time.
This enables more powerful const contexts such as const generics, const fn bodies, and compile-time calculations.
- Methods on primitive types like
u32::to_be_bytesare now const. - Slice methods such as
slice::lenandslice::is_emptyare const. - Various
OptionandResulthelpers (e.g.,Option::is_some) are const.
Adopting these const APIs can reduce runtime overhead in performance-critical code.
Frequently Asked Questions
Do I need to change existing format! calls after upgrading to Rust 1.58?
Most existing calls continue to work unchanged; only new {ident} captures are an optional addition.
Can panic! now interpolate captured identifiers in the 2021 edition?
Yes, writing panic!("{error}") will interpolate the variable error in the 2021 edition.
Will my Windows subprocess launches behave differently after the Command path change?
Executables in the current directory will no longer be found unless you add that directory to the child's PATH.
Which functions now have #[must_use] and will cause warnings if ignored?
Iterator adapters, collection transformation methods, and many std::fs and std::net functions now carry #[must_use].
How do I enable const evaluation for the newly const APIs?
Use them inside const fn or const contexts like const VAL: u32 = 42u32.to_be_bytes()[0];
Is there any breaking change in Rust 1.58?
No breaking changes were introduced; the release focuses on new features and safety improvements.