英文:
Bitmasking and Bitwise Operations in Golang
问题
我是你的中文翻译助手,以下是你要翻译的内容:
我对编程一般都是初学者,所以如果我在提问时犯了一些错误,我很抱歉。
我正在学习的教程涉及以下代码:
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)
}
教程中的人很快提到了这部分被称为位掩码(Bitmasking)。
fmt.Printf("Is Admin? %v\n", isAdmin & roles == isAdmin)
现在,据我理解,这里发生的过程大致如下:
计算机被问到是否isAdmin和roles都等于isAdmin,并回答true。
但是,当我尝试这样做时:
fmt.Printf("Is Admin? %v\n", roles == isAdmin)
结果却是false。
有人能详细解释一下这个过程背后的逻辑吗?这部分让我有点困惑,我想知道为什么会这样。谢谢。
英文:
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.
答案1
得分: 10
你的角色常量都是特殊的数字,其中二进制(2的补码)表示恰好包含一个1
位,其他位都是零,并且它们都不同(每个位置上的1
位都不同)。这是通过将数字1
左移(使用iota
)来实现的。
role
变量的值是通过使用按位或(bitwise OR)构建的:
var roles byte = isAdmin | canSeeFinancials | canSeeEurope
按位或保留1
位,在结果中,每个操作数在该位置上包含0
时,结果中将只有0
位。由于所有被OR运算的值在不同的位置上都包含一个单独的1
位,role
将包含与OR运算的不同角色数量相同的位,并且位于它们的特殊位置。
为了更容易理解这些位,让我们打印二进制表示:
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)
这将输出:
isAdmin 00000001
canSeeFinancials 00000100
canSeeEurope 00100000
-------------------------
roles 00100101
如你所见,roles
在任何上述位模式中有1
的位置上都包含1
。
当你使用按位与(掩码)时,如果给定位置上的任何输入位为0
,结果位将为0
,只有当两个位都为1
时,结果位才为1
。
表达式:
isAdmin & roles
由于isAdmin
包含一个单独的1
位,上述掩码将是一个数字,最多也只能包含一个单独的1
位,只有当roles
在该位置上有一个1
位时。实际上,这个掩码告诉我们roles
是否包含isAdmin
位。如果包含,结果将是一个等于isAdmin
的值。如果不包含,结果将是一个由所有0
位组成的数字,即十进制0
。
再次可视化这些位:
fmt.Printf("roles %08b\n", roles)
fmt.Printf("isAdmin %08b\n", isAdmin)
fmt.Printf("-------------------------\n")
fmt.Printf("isAdmin & roles %08b\n", isAdmin&roles)
输出:
roles 00100101
isAdmin 00000001
-------------------------
isAdmin & roles 00000001
在Go Playground上尝试这些示例。
因此,表达式:
isAdmin & roles == isAdmin
如果roles
包含(包括)isAdmin
角色,则为true
,否则为false
。
如果没有进行掩码操作:
roles == isAdmin
如果roles
等于isAdmin
,即它只包含isAdmin
角色和没有其他角色,那么结果将为true
。如果它包含其他角色,显然它将不等于isAdmin
。
英文:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论