Compound Assignment
Compound assignment operators combine a binary arithmetic or bitwise operation with in-place variable mutation (=). Writing x += y updates the mutable variable x by adding y to its current value.
Complete Table of Compound Assignment Operators
Rust provides ten compound assignment operators—five for arithmetic and five for bitwise manipulation:
| Operator | Category | Example | Equivalent Concept | Standard Library Trait |
|---|---|---|---|---|
+= |
Arithmetic | x += y |
x = x + y |
std::ops::AddAssign |
-= |
Arithmetic | x -= y |
x = x - y |
std::ops::SubAssign |
*= |
Arithmetic | x *= y |
x = x * y |
std::ops::MulAssign |
/= |
Arithmetic | x /= y |
x = x / y |
std::ops::DivAssign |
%= |
Arithmetic | x %= y |
x = x % y |
std::ops::RemAssign |
&= |
Bitwise / Logical | x &= y |
x = x & y |
std::ops::BitAndAssign |
|= |
Bitwise / Logical | x |= y |
x = x | y |
std::ops::BitOrAssign |
^= |
Bitwise / Logical | x ^= y |
x = x ^ y |
std::ops::BitXorAssign |
<<= |
Bitwise shift | x <<= n |
x = x << n |
std::ops::ShlAssign |
>>= |
Bitwise shift | x >>= n |
x = x >> n |
std::ops::ShrAssign |
Note: There is no
&&=or||=short-circuiting compound assignment operator in Rust. However,&=and|=work onboolvariables to perform eager boolean AND-assignment and OR-assignment.
Arithmetic Compound Assignment Examples
fn main() {
let mut balance: i32 = 100;
balance += 50; // 150
balance -= 30; // 120
balance *= 2; // 240
balance /= 3; // 80
balance %= 7; // 80 % 7 = 3
println!("Final balance: {balance}");
}
Final balance: 3
Bitwise and Boolean Compound Assignment Examples
Bitwise compound assignments are frequently used to update bitflags or accumulate boolean status checks:
fn main() {
let mut mask: u8 = 0b0000_0001;
mask <<= 3; // 0b0000_1000 (8)
mask |= 0b0000_0011; // 0b0000_1011 (11)
mask ^= 0b0000_1000; // 0b0000_0011 (3)
mask &= 0b0000_0010; // 0b0000_0010 (2)
mask >>= 1; // 0b0000_0001 (1)
println!("mask = {:08b} ({mask})", mask);
// Boolean compound assignment (`&=` and `|=`)
let mut all_valid = true;
all_valid &= 10 > 5;
all_valid &= 3 > 8; // Sets `all_valid` to `false`
println!("all_valid = {all_valid}");
}
mask = 00000001 (1)
all_valid = false
String Appending with +=
Because String implements AddAssign<&str>, the += operator appends a string slice (&str) directly onto an existing String buffer in place without allocating a separate destination String:
fn main() {
let mut greeting = String::from("Hello");
greeting += ", ";
greeting += "world!";
println!("{greeting}");
}
Hello, world!
Why Rust Has No ++ or -- Operators
Unlike C, C++, Java, Go, and JavaScript, Rust intentionally omits prefix and postfix increment (++i, i++) and decrement (--i, i--) operators. Instead, always write i += 1 or i -= 1.
Rust omits ++ and -- for two reasons:
- No hidden mutation inside sub-expressions: In C, expressions like
arr[i++] = i;orfoo(i++, ++i)mix reading a value with mutating the variable inside the same expression, leading to evaluation-order bugs and undefined behavior. - Compound assignment returns
(): Just like basic assignment (=), every compound assignment expression (i += 1) evaluates to the unit value(), making its side effect explicit and self-contained.
// ❌ does not compile
fn main() {
let mut i = 0;
i++;
}
error: Rust has no postfix increment operator
--> src/main.rs:3:6
|
3 | i++;
| ^^ not a valid postfix operator
|
help: use `+= 1` instead
|
3 - i++;
3 + i += 1;
|
error: aborting due to 1 previous error
Single Evaluation of the Left-Hand Place
In place += rhs, if place is a complex expression such as an array index scores[compute_index()] += 10, Rust evaluates compute_index() only once, whereas writing scores[compute_index()] = scores[compute_index()] + 10 would evaluate compute_index() twice:
fn get_slot() -> usize {
println!(" computing index...");
1
}
fn main() {
let mut data = [10, 20, 30];
data[get_slot()] += 5;
println!("data = {data:?}");
}
computing index...
data = [10, 25, 30]
Overflow Behavior in Compound Assignment
Arithmetic compound assignments (+=, -=, *=, /=, %=, <<=, >>=) obey the exact same overflow rules as standard binary operators (+, -, *, /, %, <<, >>):
- Debug builds: Panic on integer overflow.
- Release builds (
--release): Wrap around using two's complement arithmetic.
Common Errors
Using Compound Assignment on an Immutable Variable (E0384)
Because compound assignment mutates its left-hand operand in place via &mut self, the target variable must be declared with let mut:
// ❌ does not compile
fn main() {
let total = 10;
total += 5;
}
error[E0384]: cannot assign twice to immutable variable `total`
--> src/main.rs:3:5
|
2 | let total = 10;
| -----
| |
| first assignment to `total`
| help: consider making this binding mutable: `mut total`
3 | total += 5;
| ^^^^^^^^^^ cannot assign twice to immutable variable
error: aborting due to 1 previous error