Bitwise
The bitwise operators work on the individual bits of their operands.
| Operator | Operation | Compound form | Level |
|---|---|---|---|
~ | not (prefix) | — | 16 |
& | and | &= | 9 |
^ | exclusive or | ^= | 8 |
| | or | |= | 7 |
let a: uint8 = 0b00001100;
let b: uint8 = 0b00001010;
PrintLine("{} {} {} {}", a & b, a | b, a ^ b, ~a);
This prints 8 14 6 243: the bits set in both, in either, in exactly one, and every bit of a inverted.
Operand types
| Operand | & | ^ | ~ |
|---|---|---|
| integers | bit by bit | inverts every bit |
bool | logical and, or, exclusive or — both sides run | logical not |
| characters | bit by bit on the code | — |
The two operands follow the operand rules: one type, a literal that takes the other operand's type, or two integers of one signedness, where the narrower widens. A floating-point operand is refused:
error: operator '&' requires an integer, bool, or character left operand, but found 'float64'
error: operator '~' requires an integer or bool operand, but found 'float64'
Unsigned integers are the natural home for bit work, since none of their bits is a sign. On bool, & and | are the non-short-circuiting forms of && and || — see Logical.
Precedence
The binary bitwise operators bind more loosely than the comparisons, and among themselves & binds most tightly, then ^, then |. A test of a masked value therefore needs parentheses:
let x: int32 = 6;
let even = x & 1 == 0;
This groups as x & (1 == 0):
error: operator '&' cannot combine left operand 'int32' with right operand 'bool8'
Write (x & 1) == 0. Shifts and arithmetic bind more tightly than all three, so flags & 1 << 2 is flags & (1 << 2); parentheses still make it easier to read.
Masks and flags
With a shift to build the mask, the four single-bit operations are:
var flags: uint32 = 0;
flags |= 1 << 3;
flags &= ~(1u32 << 3);
flags ^= 1 << 2;
let isSet = (flags & (1 << 2)) != 0;
|= sets bit 3, &= with the inverted mask clears it, ^= toggles bit 2, and the last line tests it. The 1u32 in the clearing mask gives ~ a uint32 to invert. With an unsuffixed 1, ~(1 << 3) is an int, and flags &= ~(1 << 3) is error: operator '&=' cannot combine left operand 'uint32' with right operand 'int'.
Compound forms
&=, |= and ^= update a mutable place: flags |= mask is flags = flags | mask. The target must be a var or another writable place — see Assignment.
See also
- Shift — moving bits, and building masks
- Logical — the short-circuiting
&&and|| - Integers — widths and signedness
- Learn: Bitwise, Bit operation