Golang 中的位掩码和位操作

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)

现在,据我了解,这里发生的过程是这样的: 正在询问计算机 isAdminroles 是否等于 isAdmin 并回复 .

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

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

结果为 false

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

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

role 变量的值是使用按位或构造的:

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 包含 1s,其中任何上述位模式都具有 1.

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

表达式:

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

这将是 true 如果 roles 等于 isAdmin,也就是说,如果它只包含 isAdmin 角色和 nothing 否则。如果包含其他角色,显然不会等于isAdmin.