Golang 中的位掩码和按位运算

Sin*_*eth 2 boolean-logic bitmask go bitwise-operators

我是一般编程的初学者,所以如果我在提出这个问题时犯了一些错误,我很抱歉。

我正在遵循的教程介绍了此代码:

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)
}
Run Code Online (Sandbox Code Playgroud)

教程中的人很快提到了这部分如何称为Bitmasking

fmt.Printf ("Is Admin? %v\n", isAdmin & roles == isAdmin)
Run Code Online (Sandbox Code Playgroud)

现在,据我所知,这里发生的过程是这样的:计算机被询问isAdmin角色是否都等于isAdmin并回答true

但是,当我尝试这样做时:

fmt.Printf ("Is Admin? %v\n", roles == isAdmin)
Run Code Online (Sandbox Code Playgroud)

结果是false

有人可以更详细地了解这个过程背后的整个逻辑吗?这一点让我有点困惑,我想知道为什么会这样。谢谢你。

icz*_*cza 7

您的所有角色常量都是特殊数字,其中二进制(2 的补码)表示只包含一个1位,所有其他位都是零,并且它们都不同(该1位在每个位中的位置不同)。这是通过将1数字向左移动并增加值 ( iota) 来实现的。

role变量的值是通过使用按位或建造的:

var roles byte = isAdmin | canSeeFinancials | canSeeEurope
Run Code Online (Sandbox Code Playgroud)

按位或保留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)
Run Code Online (Sandbox Code Playgroud)

这将输出:

isAdmin          00000001
canSeeFinancials 00000100
canSeeEurope     00100000
-------------------------
roles            00100101
Run Code Online (Sandbox Code Playgroud)

如您所见,rolescontains 1s 其中任何上述位模式具有1.

当您使用按位与(掩码)时,结果位将是0任何输入位0位于给定位置,并且1仅当两个位都是1s时才为结果位。

表达方式:

isAdmin & roles
Run Code Online (Sandbox Code Playgroud)

由于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)
Run Code Online (Sandbox Code Playgroud)

输出:

roles            00100101
isAdmin          00000001
-------------------------
isAdmin & roles  00000001
Run Code Online (Sandbox Code Playgroud)

试试Go Playground上的例子。

所以表达式:

isAdmin & roles == isAdmin
Run Code Online (Sandbox Code Playgroud)

true如果roles包含(包括)的isAdmin作用,false否则。

无遮罩:

roles == isAdmin
Run Code Online (Sandbox Code Playgroud)

这将是trueifroles等于isAdmin,也就是说,如果它只包含isAdmin角色而不包含其他任何内容。如果它包含其他角色,它显然不会等于isAdmin.