go - 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和角色都等于isAdmin并回复true。
但是,当我尝试这样做时:
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'ed 的值在不同的位置都包含一个1
位,role
因此将包含尽可能多的不同角色 OR'ed 的位,并且在它们的特殊位置。
为了容易理解这些位,让我们打印二进制表示:
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
s ,其中任何上述位模式都有1
。
当您使用按位与(屏蔽)时,结果位将是0
如果任何输入位0
位于给定位置,并且1
仅当两个位都是1
s 时才会出现。
表达方式:
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
将是true
如果roles
包含(包含)isAdmin
角色,false
否则。
不加掩码:
roles == isAdmin
这将是true
if roles
equals to isAdmin
,也就是说,如果它只包含isAdmin
角色而没有其他内容。如果它包含其他角色,它显然不会等于isAdmin
.
推荐阅读
- laravel - querybuilder get() 上的 reverse() 更改收集结果
- javascript - Angular 5 iframe 设置宽度和高度与其内容相同
- reactjs - react-native-navigation 1.1.45 和 RN 0.43 兼容性
- database - DB2 中具有一个可为空列的复合唯一键
- excel - : 尝试打开文件夹中的所有 excel 文件,代码在 Do While FileName <> "" 之后跳过所有内容
- mysql - 忽略文本并提取 8 到 12 位数字之间的数字
- asp.net - 我的页面无故添加了额外的查询字符串参数
- three.js - Three.js:网格对象中的“向上”
- heroku - 如何在 Heroku 平台上部署 MoinMoin Wiki 服务器?
- java - SpringBoot websocket 中的messagingTemplate 是做什么用的?