Operators
From lowest to highest precedence:
| Level | Operators | Associativity |
|---|---|---|
| Logical OR | or |
left |
| Logical AND | and |
left |
| Equality | ==, != |
left |
| Relational | <, >, <=, >=, in, not in |
left |
| Bitwise OR | | |
left |
| Bitwise XOR | ^ |
left |
| Bitwise AND | & |
left |
| Shift | <<, >> |
left |
| Additive | +, - |
left |
| Multiplicative | *, /, % |
left |
| Power | ** |
left |
| Unary | -, not, ~ |
prefix |
The bitwise operators bind more tightly than comparisons, unlike C's, so
flags & MASK == 0 tests the result of &. They work on integers, not
bool: &, |, and ^ give the promoted type of their operands, ~ the
promoted type of its operand, and a shift the promoted type of the value
shifted. A shift by a negative count, or by the width of that type or more
(32 for int, 64 for i64), stops the program with a runtime error; a left
shift wraps as other arithmetic does, and a right shift of a negative number
keeps its sign. &=, |=, ^=, <<=, and >>= assign the result.
Parentheses override precedence. Logical operators emit C &&, ||, and !,
so and and or stop evaluating as soon as the result is known. Power emits
pow and is treated as an f64 expression. Its current left-associativity
means 2 ** 3 ** 2 is parsed as (2 ** 3) ** 2.
Operand types are checked:
| Operators | Operands | Result |
|---|---|---|
+, -, *, / |
two numbers | the promoted numeric type |
+ |
two strings | concatenated str |
+ |
two arrays of the same type | a new array with the elements of both |
% |
two integers | the promoted integer type |
** |
two numbers | f64 |
<, >, <=, >= |
two numbers, two chars, or two strings | bool |
==, != |
two numbers, two values of the same type, or a reference and null |
bool |
+, -, *, /, % |
two values of a struct or enum that satisfies Add, Subtract, Multiply, Divide, or Remainder |
that type, from its method |
and, or, not, unary - |
numbers or bool |
bool, or for - the promoted type of a number |
unary - |
a struct or enum that satisfies Negate |
that type, from its method |
in, not in |
a key and a map, an element and an array, or a char or str and a str |
bool |
Strings compare by content, and < and the other orderings compare them
byte by byte, as dictionaries order words in ASCII; arrays, maps, and
structs compare by identity.
key in m asks whether a map has a key, x in values whether an array holds
an element equal to x, and "ar" in text or 'a' in text whether a string
contains a piece or character. not in is the opposite. in on arrays
works for elements that are integers, bool, char, str, or plain enums.
Integer arithmetic wraps around on overflow, so 2147483647 + 1 as an int
is -2147483648. Integer / truncates toward zero, and integer / or % by
zero stops the program with a runtime error. Float division follows IEEE
rules. As in C, integers narrower than an int are worked on as ints: the
result of +, -, *, unary -, or / on two u8s is an int.
Built with --check-overflow, a program instead stops with a runtime error
when the exact result of +, -, *, unary -, /, or abs does not fit
its type, and when an integer is stored, passed, or returned as a type that
cannot hold its value, as u8 small = count can be. Where wrapping around is
meant, as in a hash, the wrapping operations say so and are never
checked. A conversion written out, as in u8(count), always wraps around.
Relational operators bind more tightly than equality operators, so
0 == 1 < 2 is parsed as 0 == (1 < 2).