Comparison Operators
Comparison operators compare two values and produce a bool result.
Equality Operators
Equality operators work on integers, booleans, strings, the unit type, and the aggregate types: structs, arrays, and enums.
| Operator | Name | Description |
|---|---|---|
== | Equal | True if operands are equal |
!= | Not equal | True if operands are not equal |
Two strings are equal if they have the same length and identical byte content.
Two unit values are always equal.
Equality on the aggregate types is structural: two aggregate values are equal if and only if they have the same type and their components — determined recursively by this rule down to scalar leaves — are equal. Specifically, two struct values are equal if and only if they have the same struct type and all corresponding fields are equal.
Two array values are equal if and only if they have the same element type and length and their elements are equal index-by-index. (Two array types of different lengths are distinct types and cannot be compared; see rule 4.3:10.)
Two enum values are equal if and only if they have the same enum type, are the same variant, and — for a variant carrying a payload — their payload fields are equal field-by-field. Two values of different variants are never equal.
A raw-pointer leaf (a *const T or *mut T field or element reached while comparing an aggregate) compares by address: two raw pointers are equal if and only if they hold the same address. The pointees are not examined.
Equality borrows its operands: evaluating a == b or a != b reads both operands without consuming them. An affine or linear value may therefore be compared without discharging its move obligation, and both operands remain usable afterward.
Equality is structural by default. Trait-based refinement of equality — opting a type out of comparison, or giving it a user-defined equality (a PartialEq-style mechanism) — is deferred until traits exist (RUE-246). A related future consideration, once floating-point types exist, is the partial-equality of NaN (where NaN != NaN), which motivates the eventual PartialEq/Eq split; today no leaf type has such a value, so structural equality is a total equivalence.
fn main() -> i32 {
let a = 1 == 1; // true
let b = 1 != 2; // true
let c = true == false; // false (bool equality)
let d = "hello" == "hello"; // true (string equality)
let e = () == (); // true (unit equality)
if a && b && !c && d && e { 1 } else { 0 }
}
struct Point { x: i32, y: i32 }
fn main() -> i32 {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 1, y: 2 };
let p3 = Point { x: 1, y: 3 };
if p1 == p2 && p1 != p3 { 1 } else { 0 }
}
Arrays compare element-by-element; nested aggregates recurse. Comparing does not consume the operands, so a and b remain usable afterward.
fn main() -> i32 {
let a = [1, 2, 3];
let b = [1, 2, 3];
let equal = a == b; // borrows a and b
if equal && a[0] == b[0] { 1 } else { 0 }
}
Ordering Operators
Ordering operators work only on integers.
| Operator | Name | Description |
|---|---|---|
< | Less than | True if left < right |
> | Greater than | True if left > right |
<= | Less or equal | True if left <= right |
>= | Greater or equal | True if left >= right |
Ordering operators on boolean, string, unit, or aggregate (struct, array, or enum) values are a compile-time error. Implementations MUST reject such programs.
fn main() -> i32 {
let a = 1 < 2; // true
let b = 5 >= 5; // true
if a && b { 1 } else { 0 }
}
Precedence
Comparison operators have lower precedence than arithmetic, shift, and bitwise operators, and higher precedence than the logical operators && and ||. (The complete precedence ladder, which matches Rust's, is given in rule 4.3a:13.)
fn main() -> i32 {
if 1 + 2 == 3 { 1 } else { 0 } // 1 (comparison after arithmetic)
}
Type Checking
Both operands of a comparison MUST have the same type.
When one operand has a known type, the other is inferred to have the same type.
Associativity
Comparison operators cannot be chained. Expressions like a < b < c or a == b == c are compile-time errors.
To compare multiple values, use logical operators:
fn main() -> i32 {
let a = 1;
let b = 2;
let c = 3;
if a < b && b < c { 1 } else { 0 } // correct way to chain comparisons
}