In the below Go file we use bitwise operators to manipulate individual flags (on/off switches) in a single integer, where each bit position represents a different status.
In case you need a reminder of a what bit alignment and shifting look like:
Each status is assigned a unique power of 2 using bit shifting (1 << iota
).
This ensures each flag only affects a single bit:
StatusActive
has the binary value0001
(1 << 0
== 1 in decimal).StatusAdmin
has the binary value0010
(1 << 1
== 2 in decimal).StatusBanned
has the binary value0100
(1 << 2
== 4 in decimal).StatusVerified
has the binary value1000
(1 << 3
== 8 in decimal).
The following example combines two separate status flags:
userStatus |= StatusActive | StatusVerified
In binary, this results in 1001
(or 9 in decimal), which means both the "active" and "verified" flags are set.
The following example sets the "admin" bit without affecting the other bits, resulting in 1011
(11 in decimal):
userStatus |= StatusAdmin
Once userStatus
has combined flags we can use the &
operator to perform a bitwise AND
operation, which means it compares each bit of two integers. For each bit position, if both bits are 1, the result at that position will be 1; otherwise, it will be 0.
So what happens when we compare userStatus&StatusAdmin != 0
?
Well, StatusAdmin
is a bit flag defined as 1 << 1
, which results in 0010
in binary. This means that StatusAdmin
occupies the second bit position in the binary representation of an integer. When we do userStatus&StatusAdmin
, we're effectively "masking" all bits except for the one represented by StatusAdmin (this is known as bit masking).
When we perform userStatus&StatusAdmin
, we get a result where only the bit corresponding to StatusAdmin
remains (and is set to 1
if that bit was already set in userStatus
). If this result is non-zero (!= 0
), it means the StatusAdmin
bit is set in userStatus
. If it's zero, then StatusAdmin
is not set in userStatus
.
If we look at the code in bitwise.go
we'll see userStatus
is initially set to include StatusActive
and StatusVerified
, so userStatus
is 1001
in binary (which is 9
in decimal). Remember StatusActive
occupied the first bit position (0001
), while StatusVerified
occupied the fourth bit position (1000
) so if setting both flags we get the combined 1001
.
Next, we add the StatusAdmin
flag with userStatus |= StatusAdmin
, making userStatus
now 1011
in binary (which is 11 in decimal). When we check if StatusAdmin
is set using userStatus&StatusAdmin != 0
we get back 2
from userStatus&StatusAdmin
(which is 0010
in binary) because we've bit masked the other bits that might have been turned on (if you recall, using &
turns each bit to zero except for those bits that were 1 in both numbers being compared), in order to reveal whether the StatusAdmin
bit was set on or not (i.e. 0
!= 2
so we know this person is an admin).