位运算符想必大家都听说过,那如何正确使用位运算呢?
今天,让我们来解决这样一个问题,用一个参数传递一组配置?
这并非是一个难题,学习过最基本的编程知识,我相信你会用 n 种方法来解决这个问题。
# 你可能的做法
配置项枚举类
/// <summary> | |
/// 配置项枚举 | |
/// </summary> | |
enum Config | |
{ | |
Item1, | |
Item2, | |
Item3 | |
} |
/// <summary> | |
/// 显示配置信息 | |
/// </summary> | |
/// <param name="configs"></param> | |
static void ShowConfigInfo(Config[] configs) | |
{ | |
foreach (var item in configs) | |
{ | |
System.Console.WriteLine(item); | |
} | |
} |
上面的做法可能是大多数人的做法,通过传递一组数据,进行数据配置的传递。
# 使用位运算的做法
首先我们需要修改枚举类以适应我们的位运算。
enum Config | |
{ | |
Item1 = 1 << 0, //1 | |
Item2 = 1 << 1, //2 | |
Item3 = 1 << 2 //4 | |
} |
修改 showConfigInfo 方法如下:
static void ShowConfigInfo (Config configs) | |
{ | |
if ((configs & Config.Item1) > 0) | |
{ | |
System.Console.WriteLine ("configs 包含 {0}", Config.Item1); | |
} | |
if ((configs & Config.Item2) > 0) | |
{ | |
System.Console.WriteLine ("configs 包含 {0}", Config.Item2); | |
} | |
if ((configs & Config.Item3) > 0) | |
{ | |
System.Console.WriteLine ("configs 包含 {0}", Config.Item3); | |
} | |
} |
调用时,只需要使用 |
运算符即可传递一组配置
ShowConfigInfo (Config.Item1 | Config.Item3); |
如上输入时输出:configs 包含 Item1 configs 包含 Item3
# 分析
首先我们先来看一下二进制码
十进制 | 二进制 |
---|---|
1 | 001 |
2 | 010 |
3 | 011 |
4 | 100 |
观察上表我们可以发现, 2的次方代表的数字,在二进制中总是只有一个1
。
然后我们再来看一下上面用到的几个位运算。
# 按位或运算 |
|
运算表示将两个操作数的二进制码进行按位或运算, 一真则真
。
例如:
- 我们计算 1|2 就是计算 001|010,结果为:011 也就是十进制 3。
- 计算 2|3 就是计算 010|011,结果为:011 也是 3。
- 计算 2|4 就是计算 010|100,结果为:110 十进制为 6
通过上面你应该可以发现,当我们将2个2的次方数进行|运算,其实就是将2者特有的标志位1 整合到一起。
这是 2 的次方数所特有的,使用这一特性我们就可以使用二进制位来存储配置。
# 按位或运算 &
&
运算表示将两个操作符的二进制进行按位与运算, 同真才为真,一假则假
例如:
- 我们计算 1&2 就是计算 001&010,结果为: 000 也就是 0
- 计算 2&3 就是计算 010&011, 结果为: 010 也就是 2
- 计算 2&4 就是计算 010&100,结果为:000 也就是 0
我们发现,当我们将2个2的次方数进行&运算,其实就是将2者所特有的标志位1 全部置为0
使用这一特性我们就可以判断数据中是否存在某一指定位为 1。
# 使用 | 组合数据 & 解析数据
通过 | 我们可以将指定位置 1
通过 & 我们可以判断是否包含指定位 1
# 其他的位操作
除了 | 和 & 还有其他位操作,比如用于加密的异或 ^, 用于补码的~,用于移位的 <<和>> 等。
使用这些位操作还能实现其他非常有趣的功能。本文重点介绍 | 和 &,其他位运算不做详细说明。
# 总结
使用 | 和 & 能够很好的按位存储和解析数据,运算效率高,能避免重复配置项,非常巧妙也十分有用!