What Is New in Rust 1.33
| Category | Highlights |
|---|---|
| New Features | Const fn enhancements, Pin API (std::pin::Pin and Unpin), ability to import items as _, Cargo now rebuilds crates when a source file changes during the initial build, crates.io requires a verified email for publishing. |
| Improvements | Numerous standard-library methods are now const (numeric overflow, rotate, wrapping, sign checks, bit-counting, byte-swap, endian conversion, NonZero::get, Ipv4Addr::new, etc.). |
How does Rust 1.33 expand the capabilities of const functions?
Rust 1.33 adds pattern destructuring, let bindings, mutable lets, assignments, and expression statements to const fn bodies.
In practice this means you can write more expressive compile-time logic without falling back to runtime code.
const fn distance((x1, y1): (i32, i32), (x2, y2): (i32, i32)) -> i32 {
let dx = x2 - x1;
let dy = y2 - y1;
let mut sum = 0;
sum += dx * dx;
sum += dy * dy;
sum
}
Additionally, const unsafe functions can be called from within a const fn, opening the door for low-level compile-time calculations.
What is the new Pin API and when should I use it?
Rust 1.33 stabilizes std::pin::Pin and the Unpin marker trait to guarantee that a value will not be moved in memory.
This matters if you are building self-referential structs or interfacing with APIs that require a stable address.
use std::pin::Pin;
struct SelfRef {
data: String,
ptr: *const String,
}
impl SelfRef {
fn new(s: String) -> Pin<Box<SelfRef>> {
let mut boxed = Box::pin(SelfRef { data: s, ptr: std::ptr::null() });
let ptr = &boxed.data as *const String;
unsafe { Pin::get_unchecked_mut(boxed.as_mut()).ptr = ptr; }
boxed
}
}
Most library authors will expose Pin-based APIs; application code typically only needs to pin futures when working with async/await once that lands.
How can I import a trait implementation without adding its name to the namespace?
Rust 1.33 lets you import an item using the underscore placeholder, effectively pulling the impls into scope while discarding the identifier.
This is handy for blanket-importing trait methods without risking name collisions.
use std::io::Read as _; // brings Read's methods into scope, but Read itself is not bound
After the import you can call read_exact on any type that implements Read without writing Read::read_exact.
What Cargo change helps with incremental builds in Rust 1.33?
Cargo now detects modifications to source files that occur during the first build and will trigger a rebuild of the affected crate.
This reduces the "missing file" race condition that could leave a crate in an inconsistent state when a generated file appears after Cargo has already decided the crate is up-to-date.
In CI pipelines you can rely on Cargo to pick up newly generated files without needing to manually clean the target directory.
Frequently Asked Questions
Can existing const functions be compiled without changes after upgrading to Rust 1.33?
Most existing const functions will continue to compile, but you can now add let bindings and assignments to make them more expressive.
Do I need to rewrite my self-referential structs to use Pin?
You only need to adopt Pin if you want the compiler to enforce that the struct's memory location never changes.
Is the import-as-underscore syntax stable for all modules?
Yes, you can use `use path::Item as _;` in any module to bring Item's impls into scope without binding the name.
Will Cargo automatically rebuild a crate if a generated file appears after the first compilation?
Cargo will now notice the change and rebuild the crate, ensuring the generated file is included.
Which standard-library numeric methods became const in Rust 1.33?
Methods like overflowing_add, rotate_left, wrapping_mul, is_positive, count_ones, swap_bytes, from_be, to_le and many others are now const.
Do I need a verified email to publish crates after Rust 1.33 was released?
Yes, crates.io now requires a verified email address before allowing cargo publish.