前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过位运算,实现单字段标识多个状态位

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

作者头像
fliter
发布2023-06-18 10:59:47
3370
发布2023-06-18 10:59:47
举报
文章被收录于专栏:旅途散记旅途散记

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

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

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

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

Linux文件和目录的权限


设计及实现

  • 左移(<<):
  • 右移(>>):
  • |(或运算):只要当一方为 true 时,结果就是 true,否则为 false。(有1就为1,全0才为0)
  • &(与运算):只有当两方都为 true 时,结果才是 true,否则为 false。(全1才为1,有0就为0)

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

如xxxxxx<<2即左移2位,右边空出的位用0填补,高位左移溢出则舍弃该高位

步骤一:

如语文成绩率先出来,我们约定,以这个字段(记为attr)的第一位,来代表该学生语文有没有通过测评(0否1是)

attr为当前该属性字段的值(从数据库里取出来的值). index为约定的第几位来标识当前业务,index从0开始计数

代码语言:javascript
复制

package main

import "fmt"

func main() {

	// 记录阶段
    //如果语文成绩测评通过,调一个写接口,初始attr值为0,约定的表示位置为第1位,又因为从0开始计数,故而index=0

	setRs := set(0, 0) //将attr字段的最新值,记录进数据库的attr字段



	// 查询阶段
	//当需要获知该学生的语文是否通过时. 查数据库,获取上面记录进的值(此时setRs即attr=1); 进而get方法,可知道是否通过(如果rs结果为1,则通过)
	rs := get(setRs, 0)
	_ = rs
}

func set(attr, index int) int {
	tmp := 1 << index
    // 1左移0位,即原地没动,还是1
	fmt.Printf("1 << index %d 值为%d:\n", index, tmp)
    // 1 | 0,或运算,有1就为1,故而setRs=1
	setRs := tmp | attr
	fmt.Println(setRs)
	
	return setRs
}

func get(attr, index int) int {
	tmp := attr >> index
    // 1右移0位,即原地不动,还是1
	fmt.Printf("attr %d >> index %d 值为 %d:\n", attr, index, tmp)
	// 0001 & 0001,与运算,全1才为1,故而为0001,即为十进制数1
	getRs := tmp & 1
	fmt.Println(getRs)

	return getRs
}

输出为:

代码语言:javascript
复制
1 << index 0 值为1:
1
attr 1 >> index 0 值为 1:
1

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

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


步骤二:

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

同样用之前的代码,

记录阶段:

代码语言:javascript
复制
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"变为"0010",即为十进制数2
	fmt.Printf("1 << index %d 值为%d:\n", index, tmp)
    // 对于语文通过带孙山,0010 | 0001,或运算,有1就为1,故而setRs=0011,即十进制数3
	// 对于语文未通过带张继,0010 | 0000,或运算,有1就为1,全0才为0, 故而setRs=0010,即十进制数2
	setRs := tmp | attr
	fmt.Println(setRs)
	
	return setRs
}
代码语言:javascript
复制
1 << index 1 值为2:
3
-----------
1 << index 1 值为2:
2

查询阶段:

代码语言:javascript
复制

package main

import "fmt"

func main() {


	// 查询阶段
	//当需要获知该学生的语文/数学是否通过时. 查数据库,获取其attr的值; 进而get方法,index字段为该科目约定的位置(语文为1,其index为0; 数学为2,其index为1),即可知道是否通过(如果rs结果为1,则通过)
	sunMath := get(setRsSun, 1) //setRsSun=3

	fmt.Println("-----------")
	zhangChinese := get(setRsZhang, 0)//setRsZhang=2


	fmt.Println("sunMath is:",sunMath)
	fmt.Println("zhangChinese is:",zhangChinese)
}


func get(attr, index int) int {
	tmp := attr >> index
   
	
	fmt.Printf("attr %d >> index %d 值为 %d:\n", attr, index, tmp)
	
	getRs := tmp & 1
	fmt.Println(getRs)

	return getRs
}
代码语言:javascript
复制
 // 对于孙山,十进制数3即二进制0011,右移1位,即0001,即十进制数1
attr 3 >> 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×201×258+1×257…+1×22+1×21+1×20,

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

2的n次方对照表

第60门课’信息技术’也高分通过, 则对于最新的attr值,即 1 << index | attr,

1 << 59 | 576460752303423487 = 1152921504606846975,将这个值计入数据库.

如需获取爽哥有无通过第60门课程,1152921504606846975 >> 59 & 1 = 1,即通过

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


更通用的代码:

代码语言:javascript
复制

func main(){

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

}

func SetAttrBit(attr int, index uint8) int {
	return 1 << index | attr
}


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

参考:

用位运算来标识状态


番外

“光学电报”

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 旅途散记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 设计及实现
  • 番外
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档