As a low-level language, Rust has excellent support for bitwise operators. But some syntax tricks are required. The standard library provides many helpful functions.
For bitwise not, which is used to set a bit to 0, we must use the exclamation mark in Rust. The compiler helpfully tells us how to fix these statements.
Suppose we have an i32
value and want to set one of its 32 bits to 1. And then we want to set that same bit to 0 at some point.
i32
value, but since there are 32 bits, we could use any number from 0 to 31 inclusive.fn main() { let mut value = 0; let bit_pos = 5; // Set bit to 1. value |= 1 << bit_pos; // Test set bit. if value & (1 << bit_pos) != 0 { println!("Bit is set to 1"); } // Ensure this bit is still set to 0. if value & (1 << bit_pos + 1) == 0 { println!("Bit is set to 0"); } // Set the bit to 0. value &= !(1 << bit_pos); // Ensure newly set bit is 0. if value & (1 << bit_pos) == 0 { println!("Bit was changed to 0"); } }Bit is set to 1 Bit is set to 0 Bit was changed to 0
In Rust we do not need to write our own bit count function—we can use a built-in function to count bits set to 1 in an i32
value. We call the count_ones
function.
trailing_zeros
function is helpful. It can tell us the last bit set to 1 in an integer.trailing_zeros
, we can loop over the positions of set bits in an integer. This can help some algorithms like tree searches.fn main() { // Can use count ones for bit counting. let mut value = 0; let count = i32::count_ones(value); println!("COUNT: {}", count); value |= 1 << 3; let count = i32::count_ones(value); println!("COUNT: {}", count); // Can compute the last set bit index with trailing zeros. let trailing = i32::trailing_zeros(value); println!("TRAILING: {}", trailing); }COUNT: 0 COUNT: 1 TRAILING: 3
When setting a bit to 0, we want to use an AND with a bitwise NOT expression. But in Rust, this syntax is different than in C.
fn main() { let mut value = 0; value &= ~(1 << 4); // Compile error. }error: ~ cannot be used as a unary operator ... help: use ! to perform bitwise not
Handling bits is well-supported in Rust, and this language can be used for low-level tasks. Bitwise operations help improve performance, and reduce memory usage, in large data structures.