Golang中的位掩码和位运算

5

我是一个编程新手,如果我在提出这个问题时犯了一些错误,我很抱歉。

我正在学习的教程涉及到以下代码:

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)
}

教程中的这位男士迅速提到了这个部分被称为位掩码

fmt.Printf ("Is Admin? %v\n", isAdmin & roles == isAdmin)

据我所了解,这里发生的过程大致如下:

电脑被询问是否同时具有isAdminroles等于isAdmin,并回答true

但是,当我尝试做到这一点时:

fmt.Printf ("Is Admin? %v\n", roles == isAdmin)

结果为false

有人能否更详细地讲解这个过程的整个逻辑?这一部分让我有些困惑,我想知道为什么会发生这种情况。谢谢。


1
&按位与, 而 && 则是逻辑与。你所描述的应该是 isAdmin == isAdmin && roles == isAdmin(这并没有太多意义)。链接的维基百科页面详细介绍了位掩码。请仔细阅读。 - Marc
1个回答

10

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

role变量的值是通过使用按位或(bitwise OR)构造的:

var roles byte = isAdmin | canSeeFinancials | canSeeEurope

位或运算会保留所有的二进制数中的 1 位,而在结果中,每个操作数在相应位置上都为 0 的位也都将是 0。由于所有进行位或的值在不同的位置上都只包含一个 1 位,因此 role 变量将包含与进行位或的不同角色数量相同的位数,并且这些位数在特定的位置上。

为了更容易理解二进制位,请打印其二进制表示:

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 的位。

当您使用按位与(掩码)时,如果给定位置的任一输入位为 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角色,即不包含其他角色,则此值将为true。如果它包含其他角色,则显然不等于 isAdmin


谢谢!虽然位掩码的概念仍然很难理解,但现在提供的代码更容易理解了!我会花时间更彻底地研究掩码以更好地理解它。 - Sinoreth
1
@Sinoreth 添加了位的可视化表示,使理解更加容易。 - icza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接