Operators and Expressions

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 on bool variables 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:

  1. No hidden mutation inside sub-expressions: In C, expressions like arr[i++] = i; or foo(i++, ++i) mix reading a value with mutating the variable inside the same expression, leading to evaluation-order bugs and undefined behavior.
  2. 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