通过位运算,实现单字段标识多个状态位

2023年 10月 7日 77.5k 0

可能经常有如下这种需求: 需要一张表,来记录学员课程的通过与否. 课程数量不确定,往往很多,且会有变动,随时可能新增一门课.

这种情况下,在设计表结构时,一门课对应一个字段,就有些不合适, 因为不知道课程的具体数量,也无法应对后期课程的增加.

考虑只用一个状态标志位,利用位运算,来标识多门课的通过或否.

这与Linux的文件权限思路一致

Linux文件和目录的权限

设计及实现

  • 左移():

  • |(或运算):只要当一方为 true 时,结果就是 true,否则为 false。 (有1就为1,全0才为0)

  • &(与运算):只有当两方都为 true 时,结果才是 true,否则为 false。(全1才为1,有0就为0)

对于正数和负数,左移一位就相当于乘以2的1次方,左移n位就相当于乘以2的n次方

如xxxxxx index 0 值为 1:
1

假设孙山语文及格, 张继语文落榜(则不调用写接口,只有通过才调),则二人当前attr的值为1和0.

这样就完成了语文科目的处理

步骤二:

几天后数学测评结果也出来了,继续用attr,约定以这个字段的第二位,来代表该学生数学有没有通过测评(0否1是)

同样用之前的代码,

记录阶段:

package main

import "fmt"

func main() {

	// 记录阶段
    //如果数学成绩测评通过,调写接口,约定的表示位置为第1位,又因为从0开始计数,故而index=1
	// 对于孙山,从数据库取出其attr值,为1; 张继的attr值为0

	// 加入二人都通过了数学测评,都需调用如下写接口

	setRsSun := set(1, 1) //将attr字段的最新值,记录进数据库的attr字段
	fmt.Println("-----------")
	setRsZhang := set(0, 1)

}

func set(attr, index int) int {
	tmp := 1 > index 1 值为 1:
// 0001 & 0001,与运算,全1才为1,故而为1. 即孙山通过了数学
1
-----------
// 对于张继,十进制数2即二进制0010,右移0位,即原地不动,还是0010,十进制数2
attr 2 >> index 0 值为 2:
// 0010 & 0001,全1才为1,否则为0. 即张继没有通过语文
0

sunMath is: 1
zhangChinese is: 0

步骤三:

过了几天,英语结果也出来了.假如孙山没通过,张继通过,爽哥三门都通过,则有

写入和读取过程同上

步骤四:

假如现在第60个科目'信息技术'的测评出炉, 爽哥前面59门课程全部通过,则attr字段的值为1×258+1×257...+1×22+1×21+1×201times2^{58}+1times2^{57} ... + 1times2^2 + 1times2^1 + 1times2^01×258+1×257...+1×22+1×21+1×20,

即 288230376151711744+144115188075855872...+4+2+1=576460752303423487288230376151711744 + 144115188075855872 ...+4+2+1 = 576460752303423487288230376151711744+144115188075855872...+4+2+1=576460752303423487

2的n次方对照表

第60门课'信息技术'也高分通过, 则对于最新的attr值,即 1 59 & 1 = 1,即通过

如果将数据库这个attr字段设置为有符号的bigint类型,则最多可标识 60几个不同业务的状态

更通用的代码:


func main(){

	index := uint8("约定的位置" - 1)
	attr := "来自数据库"

}

func SetAttrBit(attr int, index uint8) int {
	return 1 > index & 1
}

参考:

用位运算来标识状态

番外

"光学电报"

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论