Rust 2024 Edition
Edition-Specific Best Practices
Writing idiomatic Rust 2024 edition code takes advantage of the edition's cleaner lifetime defaults, stricter unsafe boundaries, unified Cargo resolver, and modern standard library additions to eliminate legacy boilerplate.
Rust 2024 Idiomatic Checklist:
1. Manifest: `edition = "2024"` + `rust-version = "1.85"` (activates MSRV Resolver v3)
2. Prelude: Use `Future` and `IntoFuture` directly without `use std::future::...`
3. Lifetimes: Let `-> impl Trait` capture lifetimes automatically; use `+ use<...>` to restrict
4. Strings/FFI: Use `c"literal"` for static `CStr`s, `unsafe extern "C"`, & `#[unsafe(no_mangle)]`
5. Unsafe Code: Keep `unsafe_op_in_unsafe_fn = "deny"` and replace `static mut` with Atomics/Locks
6. Control Flow: Flatten nested conditionals with `if let ... && ...` let-chains and `let ... else`
7. Lints: Use `#[expect(lint, reason = "...")]` instead of `#[allow(lint)]`
Comparing Legacy Idioms vs Rust 2024 Best Practices
| Task | Pre-2024 Workaround / Legacy Style | Idiomatic Rust 2024 Best Practice |
|---|---|---|
| Static C-String Literal | CStr::from_bytes_with_nul(b"hi\0").unwrap() |
c"hi" (&'static CStr validated at compile time) |
Returning Borrowed impl Iterator |
-> impl Iterator<Item = T> + '_ |
-> impl Iterator<Item = T> (captures in-scope lifetimes automatically) |
Excluding a Lifetime from impl Trait |
Custom Captures trait trick |
-> impl Trait + use<'kept, T> |
Consuming a Box<[T]> by Value |
Vec::from(boxed_slice).into_iter() |
boxed_slice.into_iter() (yields owned T directly in 2024!) |
| Suppressing a Local Warning | #[allow(dead_code)] |
#[expect(dead_code, reason = "...")] (warns when obsolete!) |
| Raw Pointer to Packed / Static Field | std::ptr::addr_of!(s.field) |
&raw const s.field / &raw mut s.field |
| Inline Compile-Time Assertion / Table | Separate const TMP: ... = ...; item |
const { assert!(N > 0); N * 2 } inline const block |
Complete Showcase of Idiomatic Rust 2024 Code
#![deny(unsafe_op_in_unsafe_fn)]
use core::ffi::CStr;
/// Uses Rust 2024 inline `const { ... }` block to enforce compile-time capacity invariants!
pub struct FixedPacket<const CAP: usize> {
buf: [u8; CAP],
len: usize,
}
impl<const CAP: usize> FixedPacket<CAP> {
pub const fn new() -> Self {
// Inline `const` block evaluated at monomorphization / compile time:
const {
assert!(CAP > 0 && CAP <= 4096, "CAP must be in 1..=4096");
}
Self {
buf: [0u8; CAP],
len: 0,
}
}
}
/// Uses Rust 2024 `Future` directly from the prelude, `c"..."` literal,
/// `Box<[T]>::into_iter()` by value, and `-> impl Iterator` automatic lifetime capture!
pub fn filter_valid_tags<'a>(
tags: Box<[&'a str]>,
required_prefix: &str,
) -> impl Iterator<Item = &'a str> {
let default_c_tag: &'static CStr = c"default_tag";
assert_eq!(default_c_tag.to_bytes(), b"default_tag");
// In Rust 2024:
// 1. `tags.into_iter()` yields `&'a str` by value directly from `Box<[&'a str]>`!
// 2. `-> impl Iterator` captures both `'a` and `required_prefix`'s lifetime automatically!
tags.into_iter()
.filter(move |t| t.starts_with(required_prefix))
}
fn main() {
let _pkt = FixedPacket::<256>::new();
let boxed_tags: Box<[&str]> = Box::new(["v1:auth", "v2:metrics", "v1:storage"]);
let prefix = String::from("v1:");
let matching: Vec<&str> = filter_valid_tags(boxed_tags, &prefix).collect();
assert_eq!(matching, vec!["v1:auth", "v1:storage"]);
// Native `&raw const` pointer creation syntax (replaces `ptr::addr_of!`):
let x = 42u32;
let raw_ptr: *const u32 = &raw const x;
assert!(raw_ptr.is_aligned());
println!("Rust 2024 showcase matched tags: {matching:?}");
}
Rust 2024 showcase matched tags: ["v1:auth", "v1:storage"]