Reputation: 61
I'm a beginner to programming in general so i'm sorry if i make some mistakes while putting this question up.
The tutorial I'm following goes over this code:
package main
import (
"fmt"
)
const (
isAdmin = 1 << iota
isHeadquarters
canSeeFinancials
canSeeAfrica
canSeeAsia
canSeeEurope
canSeeNorthAmerica
canSeeSouthAmerica
)
func main() {
var roles byte = isAdmin | canSeeFinancials | canSeeEurope
fmt.Printf ("%b\n", roles)
fmt.Printf ("Is Admin? %v\n", isAdmin & roles == isAdmin)
}
The guy in tutorial quickly mentions how this part is called Bitmasking.
fmt.Printf ("Is Admin? %v\n", isAdmin & roles == isAdmin)
Now, as far as i understand, the process that takes place here goes something like this: The computer is being asked if both isAdmin and roles are equal to isAdmin and replies true.
But, when i'm trying to do this:
fmt.Printf ("Is Admin? %v\n", roles == isAdmin)
It results in false.
Can somebody go in greater detail on the whole logic behind this process? This bit leaves me a bit confused and i want to know why that happens. Thank you.
Upvotes: 5
Views: 5250
Reputation: 417612
All your role constants are special numbers where the binary (2's complement) representation contains exactly a single 1
bit, all other bits are zeros, and they are all different (the 1
bit is in a different position in each). This is achieved by shifting the 1
number to the left with increasing values (iota
).
The role
variable's value is constructed by using bitwise OR:
var roles byte = isAdmin | canSeeFinancials | canSeeEurope
Bitwise OR keeps 1
bits, and in the result there will only be 0
bits where each operand contains 0
in that position. Since all values being OR'ed contain a single 1
bit in different positions, role
will contain as many bits as many different roles OR'ed, and at their special positions.
To easily understand the bits, let's print the binary representations:
fmt.Printf("isAdmin %08b\n", isAdmin)
fmt.Printf("canSeeFinancials %08b\n", canSeeFinancials)
fmt.Printf("canSeeEurope %08b\n", canSeeEurope)
fmt.Printf("-------------------------\n")
fmt.Printf("roles %08b\n", roles)
This will output:
isAdmin 00000001
canSeeFinancials 00000100
canSeeEurope 00100000
-------------------------
roles 00100101
As you can see, roles
contains 1
s where any of the above bit patterns has 1
.
When you use bitwise AND (masking), the result bit will be 0
if any of the input bit is 0
at a given position, and will be 1
only if both bits are 1
s.
The expression:
isAdmin & roles
Since isAdmin
contains a single 1
bit, the above masking will be a number that may also contain a single 1
bit at most, only if roles
has a 1
bit at that position. Effectively this masking tells if roles
contains the isAdmin
bit. If it contains it, the result will be a value equal to isAdmin
. If not, the result will be a number consisting all 0
bits, that is: decimal 0
.
Visualizing the bits again:
fmt.Printf("roles %08b\n", roles)
fmt.Printf("isAdmin %08b\n", isAdmin)
fmt.Printf("-------------------------\n")
fmt.Printf("isAdmin & roles %08b\n", isAdmin&roles)
Output:
roles 00100101
isAdmin 00000001
-------------------------
isAdmin & roles 00000001
Try the examples on the Go Playground.
So the expression:
isAdmin & roles == isAdmin
Will be true
if roles
contains (includes) the isAdmin
role, false
otherwise.
Without masking:
roles == isAdmin
This will be true
if roles
equals to isAdmin
, that is, if it only contains the isAdmin
role and nothing else. If it contains other roles, it obviously won't be equal to isAdmin
.
Upvotes: 10