Rust Number Overflow
Overflow is a result that does not fit in its number type. Rust handles overflow in ways that depend on the build and the method used.
Wrap on purpose: wrapping_add
wrapping_add steps past the top and wraps around — 255 + 1 becomes 0:
let m: u8 = 255;
println!("wrap = {}", m.wrapping_add(1));Ask first: checked_add
checked_add gives an Option: the sum, or None when it overflows — an answer you must handle:
let m: u8 = 255;
println!("checked = {:?}", m.checked_add(1));Stop at the edge: saturating_add
saturating_add climbs to the maximum and stays there, however far past it the sum would land:
let m: u8 = 255;
println!("saturate = {}", m.saturating_add(10));The value plus a flag: overflowing_add
overflowing_add gives both pieces of news: the wrapped value, and true or false to say whether it overflowed:
let m: u8 = 255;
let pair = m.overflowing_add(1);
println!("value = {} overflowed = {}", pair.0, pair.1);Plain + depends on the build
In a debug build (cargo run), Rust checks every sum and the program panics on overflow. In a release build the checks are off for speed, and the value wraps silently. The numbers are visible like this. Then the compiler refuses the sum while compiling. The next lesson runs it both ways. That lesson is Overflow in Debug and Release:
let m: u8 = 255;
let total = m + 1;
println!("total = {}", total);Example
fn main() {
let m: u8 = 255;
println!("wrap = {}", m.wrapping_add(1));
println!("checked = {:?}", m.checked_add(1));
println!("saturate = {}", m.saturating_add(10));
let pair = m.overflowing_add(1);
println!("overflow pair = {} {}", pair.0, pair.1);
}Key points
- Overflow: a result that does not fit in the type, like 255 + 1 in a u8
- Wrapping is silent: no error, just a wrong-looking answer, so never rely on it by accident
- You can also set the rule for a whole project: overflow-checks = true under [profile.release] in Cargo.toml keeps release builds checking — the Overflow in Debug and Release lesson, next, puts it to work
In this example, m is a u8 at its maximum, 255. wrapping_add(1) steps past the top and wraps to 0. checked_add(1) refuses and gives None — an Option you must handle. saturating_add(10) would land at 265, far past the top, so it stops at 255 instead. overflowing_add(1) gives both pieces of news: the wrapped value 0, and true to say yes, it overflowed. Four methods, four clear answers to the same problem — you pick per sum, not per program.
Note
Many languages wrap silently in every build.
Rust shouts during development, when mistakes are cheap, and lets you pick the rule for the final build.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
In a debug build, what happens when plain + makes a u8 pass 255?