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

2023-10-08 03:04

本文主要是介绍通过位运算,实现单字段标识多个状态位,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

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

这与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.chinasem.cn/article/162261

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin