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

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

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

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

这与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开始计数


package main

import "fmt"

func main() {

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

 setRs := set(00//将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
}



输出为:

1 << index 0 值为1:
1
attr 1 >> index 0 值为 1:
1

alt

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

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




步骤二:


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


同样用之前的代码,

记录阶段:

package main

import "fmt"

func main() {

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

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

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

}

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
}


1 << index 1 值为2:
3
-----------
1 << index 1 值为2:
2

alt

查询阶段:


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
}



 // 对于孙山,十进制数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




步骤三:


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

alt

写入和读取过程同上



步骤四:


假如现在第60个科目'信息技术'的测评出炉, 爽哥前面59门课程全部通过,则attr字段的值为 ,

2的n次方对照表

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

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


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


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




更通用的代码:


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
}


参考:

用位运算来标识状态




番外


alt

"光学电报"

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/151442.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【软考】9.1 顺序表/链表/栈和队列

《线性结构》 顺序存储和链表存储 每个元素最多只有一个出度和一个入度&#xff0c;表现为一条线状链表存储结构&#xff1a;每个节点有两个域&#xff0c;即数据&#xff0c;指针域&#xff08;指向下一个逻辑上相邻的节点&#xff09; 时间复杂度&#xff1a;与其数量级成正…

微信小程序使用路由传参和传对象的方法

近期在做微信小程序开发&#xff0c;在页面跳转时&#xff0c;需要携带参数到下一个页面&#xff0c;尤其是将对象传入页面。为了方便重温&#xff0c;特此记录。 路由传字符串参数 原始页面 传递字符串参数比较简单。路由跳转有两种方式&#xff0c;一种是通过navigator组件…

【Java接口性能优化】skywalking使用

skywalking使用 提示&#xff1a;微服务中-skywalking使用 文章目录 skywalking使用一、进入skywalking主页二、进入具体服务1.查看接口 一、进入skywalking主页 二、进入具体服务 可以点击列表或搜索后&#xff0c;点击进入具体服务 依次选择日期、小时、分钟 1.查看接口 依次…

聊天、会议、多媒体一体化:多平台支持的即时通讯系统 | 开源日报 No.44

harness/gitness Stars: 28.2k License: Apache-2.0 Gitness 是一个建立在 Drone 之上的新型开源开发者平台&#xff0c;具备代码托管和流水线功能。它提供了以下核心优势&#xff1a; 轻量级、超快速的代码托管和持续集成服务支持 Docker 容器化部署可以在本地环境中构建和…

【Acwing1010】拦截导弹(LIS+贪心)题解

题目描述 思路分析 本题有两问&#xff0c;第一问直接用lis的模板即可&#xff0c;下面重点看第二问 思路是贪心&#xff1a; 贪心流程&#xff1a; 从前往后扫描每一个数&#xff0c;对于每个数&#xff1a; 情况一&#xff1a;如果现有的子序列的结尾都小于当前的数&…

【网络安全 --- kali2023安装】超详细的kali2023安装教程(提供镜像资源)

如果你还没有安装vmware 虚拟机&#xff0c;请参考下面博客安装 【网络安全 --- 工具安装】VMware 16.0 详细安装过程&#xff08;提供资源&#xff09;-CSDN博客【网络安全 --- 工具安装】VMware 16.0 详细安装过程&#xff08;提供资源&#xff09;https://blog.csdn.net/m0…

Unity可视化Shader工具ASE介绍——3、ASE的Shader类型介绍

大家好&#xff0c;我是阿赵。这里继续介绍Unity可视化Shader编辑插件ASE的用法。   上一篇介绍了节点的输入输出节点。这一篇来介绍一下不同的Shader类型的区别。 一、修改Shader类型 之前介绍创建Shader的时候&#xff0c;曾经说过可以选择Shader的类型。 其实这个类型是…

【版本控制工具一】Git 安装注册及使用

文章目录 一、Git 、Github、Gitee1.1 概述1.2 码云 相对于 github 的优势 二、Github 或 Gitee注册2.1 注册2.2 创建仓库 三、Git下载与安装四、创建本地仓库 一、Git 、Github、Gitee 1.1 概述 Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或…

c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))

上篇文章介绍了一些常用的字符串函数&#xff0c;大家可以跳转过去浏览一下&#xff1a;c语言进阶部分详解&#xff08;详细解析字符串常用函数&#xff0c;并进行模拟实现&#xff08;上&#xff09;&#xff09;_总之就是非常唔姆的博客-CSDN博客 今天接着来介绍一些&#x…

扭线机控制

扭线机属于线缆加工设备&#xff0c;线缆加工设备种类非常多。有用于网线绞合的单绞&#xff0c;双绞机等&#xff0c;有关单绞机相关算法介绍&#xff0c;大家可以查看专栏相关文章&#xff0c;有详细介绍&#xff0c;常用链接如下&#xff1a; 线缆行业单绞机控制算法&#…

性能测试笔记

一、性能测试的概念 性能测试的概念 使用自动化工具&#xff0c;模拟不同的场景&#xff0c;对软件各项性能指标进行测试和评估的过程 性能测试的目的 评估当前系统能力&#xff0c;出现性能bug后&#xff0c;优化性能&#xff1a;预测未来的性能需求是否满足 例如&#xf…

【软考】8.2 编译程序基本原理/文法/正规式/有限自动机

《编译程序基本原理》 编译过程 词法分析&#xff1a; 针对单词&#xff1b;输入是字符&#xff1b;读的是字符流&#xff1b;语法分析&#xff1a; 针对语句&#xff1b;读的是记号流&#xff0c;即词法分析产生的一个个单词语义分析&#xff08;针对语句含义&#xff09; a.…

Golang interface 接口的应用场景 使用细节

应用场景介绍 对初学者讲&#xff0c;理解接口的概念不算太难&#xff0c;难的是不知道什么时候使用接口&#xff0c;下面我例举几个应用场景&#xff1a; 1.说现在美国要制造轰炸机&#xff0c;武装直升机&#xff0c;专家只需把飞机需要的功能/规格定下来即可&#xff0c;然…

Sql server 使用DBCC Shrinkfile 收缩日志文件

磁盘空间有限&#xff0c;需要收缩日志文件释放空间。 数据库名称上右击属性->文件,逻辑名称日志文件默认名称为“_log”结尾。 alter database 数据库 set recovery simple dbcc shrinkfile(XXX_log,2,truncateonly) alter database 数据库 set recovery full

【Vue2.0源码学习】生命周期篇-销毁阶段(destroy)

文章目录 1. 前言2. 销毁阶段分析3. 总结 1. 前言 接下来到了生命周期流程的最后一个阶段——销毁阶段。从官方文档给出的生命周期流程图中可以看到&#xff0c;当调用了vm.$destroy方法&#xff0c;Vue实例就进入了销毁阶段&#xff0c;该阶段所做的主要工作是将当前的Vue实例…

Vue 3 学习 源码解读

该文章内容为以下视频的学习笔记&#xff1a; 前言_哔哩哔哩_bilibili前言是秋招解决方案&#xff1a;深入 Vue3 源码&#xff0c;带你彻底打通 Vue3 源码面试的第1集视频&#xff0c;该合集共计13集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。htt…

微信小程序——CSS3渐变

SS3 渐变&#xff08;gradients&#xff09;可以在两个或多个指定的颜色之间显示平稳的过渡。CSS3 定义了两种类型的渐变&#xff08;gradients&#xff09;&#xff1a; 说明 1、线性渐变&#xff08;Linear Gradients&#xff09;- 向下/向上/向左/向右/对角方向&#xff1…

Spring AOP 详解及@Trasactional

Spring AOP 详解 AOP基础 AOP: Aspect Oriented Program, 面向切面编程。解耦&#xff08;组织结构调整&#xff09;、增强&#xff08;扩展&#xff09;。 AOP术语 术语 说明 Aspect&#xff08;切面&#xff09; 横切于系统的连接点实现特定功能的类 JoinPoint&#xf…

编译工具链 之二 详解 ELF 格式及标准、UNIX 发展、ABI

在计算机及嵌入式系统中&#xff0c;二进制文件也有一定的标准格式&#xff0c;通常会包含在各平台的应用程序二进制接口 &#xff08;Application Binary Interface&#xff0c;ABI&#xff09;规范中。它是编译工具链必须要遵守的规范&#xff08;编译工具链产生符合 ABI 的二…

Qt单一应用实例判断

原本项目中使用QSharedMemory的方法来判断当前是否已存在运行的实例&#xff0c;但在MacOS上&#xff0c;当程序异常崩溃后&#xff0c;QSharedMemory没有被正常销毁&#xff0c;导致应用程序无法再次被打开。 对此&#xff0c;Qt assistant中有相关说明&#xff1a; 摘抄 qt-s…