5.6 Operators
Rust supports most standard operators familiar from C/C++.
- Arithmetic:
+
(add),-
(subtract),*
(multiply),/
(divide),%
(remainder/modulo). - Comparison:
==
(equal),!=
(not equal),<
(less than),>
(greater than),<=
(less than or equal),>=
(greater than or equal). These return abool
. - Logical:
&&
(logical AND, short-circuiting),||
(logical OR, short-circuiting),!
(logical NOT). Operate onbool
values. - Bitwise:
&
(bitwise AND),|
(bitwise OR),^
(bitwise XOR),!
(bitwise NOT - unary, only for integers),<<
(left shift),>>
(right shift). Operate on integer types. Right shifts on signed integers perform sign extension; on unsigned integers, they shift in zeros. - Assignment:
=
(simple assignment). - Compound Assignment:
+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
,<<=
,>>=
. Combines an operation with assignment (e.g.,x += 1
is equivalent tox = x + 1
). - Unary:
-
(negation for numbers),!
(logical NOT forbool
, bitwise NOT for integers),&
(borrow/reference),*
(dereference). - Type Casting:
as
(e.g.,let float_val = integer_val as f64;
). Explicit casting is often required between numeric types. - Grouping:
()
changes evaluation order. - Access:
.
(member access for structs/tuples),[]
(index access for arrays/slices/vectors).
Key Differences/Notes for C Programmers:
- No Increment/Decrement Operators: Rust does not have
++
or--
. Usex += 1
orx -= 1
instead. This avoids ambiguities present in C regarding pre/post increment/decrement return values and side effects within expressions. - Strict Type Matching: Binary operators (like
+
,*
,&
,==
) generally require operands of the exact same type. Implicit numeric promotions like in C (e.g.,int + float
) do not happen. You must explicitly cast usingas
.#![allow(unused)] fn main() { let a: i32 = 10; let b: u8 = 5; // let c = a + b; // Compile Error: mismatched types i32 and u8 let c = a + (b as i32); // OK: b is explicitly cast to i32 println!("c = {}", c); }
- No Ternary Operator: Rust does not have C’s
condition ? value_if_true : value_if_false
. Use anif
expression instead, which is more readable and less prone to precedence errors:#![allow(unused)] fn main() { let condition = true; let result = if condition { 5 } else { 10 }; println!("Result = {}", result); }
- Operator Overloading: You cannot create new custom operators, but you can overload existing operators (like
+
,-
,*
,==
) for your own custom types (structs, enums) by implementing corresponding traits from thestd::ops
module (e.g.,Add
,Sub
,Mul
,PartialEq
). This allows operators to work intuitively with user-defined types like vectors or complex numbers.
In addition to the operators mentioned earlier, Rust uses &
to create references or to specify that a type is a reference, and *
to dereference a reference in order to access the original value it points to.
Operator Precedence: Largely follows C/C++ conventions (e.g., *
and /
before +
and -
, comparisons before logical operators). Use parentheses ()
to clarify or force a specific evaluation order when in doubt – clarity is usually preferred over relying on subtle precedence rules.