首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
command
dagger
runtime
string
grid
jar
rsa
callback
web3
express
instance
frameworks
input
expression
copy
const
php
javascript
web
client
flutter
less
controller
hook
cmd
window
byte
eval
golang
keyword
cookie
export
md5
config
vba
subset
bit
heatmap
email
solr
tags
httprequest
random
object
tree
select
python3
io
substring
uri
join
bash
format
blob
emoji
cpython
yaml
default
match
testing
数组
regex
post
ip
perl
filter
hashcode
hash
get
httpclient
main
buffer
timezone
function
vbscript
php8
case
cSharp
schema
当前位置:
开发笔记
>
编程语言
> 正文
深入解析Go语言中的位操作技术
作者:多少年都不会变 | 来源:互联网 | 2024-10-26 11:29
![cover](https://raw.githubusercontent.com/studygolang/gctt-images/master/go-bits/cover.png)
在以前内存和处理能力(CPU)都是非常昂贵的,于是直接在位上编程就成为了处理信息的首选方式(在有些情况下也是唯一的方式)。如今,直接对位进行操作在底层系统、图像处理和密码学等领域还是至关重要的。
在 Go 语言中支持以下几种操作位的方式:
```
& 位与
| 位或
^ 异或
&^ 位与非
<<左移
>> 右移
```
接下来我们会对每一个操作符进行详细的讨论并给出一些可以应用位操作的实例。
## `&` 操作符
在 Go 中,`&` 操作符用来在两个整数之间进行位 AND 运算。AND 操作有以下特性:
```
Given operands a, b
AND(a, b) = 1; only if a = b = 1
else = 0
// 给定 2 个操作数 a,b:
// 当且仅当 a 和 b 都为 1 时,操作 AND(a, b) 的结果为 1。
// 否则操作 AND(a, b) 为 0。
```
AND 操作符是一个很好的将整数的指定位清零的方式。在下面的例子中,我们使用 `&` 运算符将数字后 4 位清零。
```go
func main() {
var x uint8 = 0xAC // x = 10101100
x = x & 0xF0 // x = 10100000
}
```
所有的二进制操作符都支持简写形式,我们可以把上面的例子改为简写形式:
```go
func main() {
var x uint8 = 0xAC // x = 10101100
x &= 0xF0 // x = 10100000
}
```
另外一个小技巧就是可以通过 `&` 来判断一个数字是奇数还是偶数。我们可以将数字和值 1 使用 `&` 做 AND 运算。如果结果是 1,那说明原来的数字是一个奇数。
```go
import (
"fmt"
"math/rand"
)
func main() {
for x := 0; x <100; x {
num := rand.Int()
if num&1 == 1 {
fmt.Printf("%d is odd\n", num)
} else {
fmt.Printf("%d is even\n", num)
}
}
}
```
[在线运行](https://play.golang.org/p/2mTNOtioNM)
## `|` 操作符
`|` 用来做数字的位 OR 运算。OR 操作符有以下特性:
```
Given operands a, b
OR(a, b) = 1; when a = 1 or b = 1
else = 0
// 给定两个操作数 a,b
// 当且仅当 a 和 b 均为 0 时,操作 OR(a, b) 返回 0。
// 否者返回 1。
```
我们可以使用这个特性来将一个整数中的指定位置为 1。在下面的例子里,我们使用 OR 运算将第 3、7、8 位置为 1。
```go
func main() {
var a uint8 = 0
a |= 196
fmt.Printf("%b", a)
}
// prints 11000100
^^ ^
```
[在线运行](https://play.golang.org/p/3VPv4D83Oj)
当对一个数字使用掩码技术,OR 是非常有用的。下面的例子我们可以设置更多的位:
```go
func main() {
var a uint8 = 0
a |= 196
a |= 3
fmt.Printf("%b", a)
}
// prints 11000111
```
[在线运行](https://play.golang.org/p/7aJLwh3y4x)
在上面的例子中,我们不仅有数字 196 中的所有位,而且最后的两位也被数字 3 置 1。我们可以一直进行置 1 操作,直到所有的位都为 1。
### 使用位作为配置信息
现在,回顾 `AND(a,1) = a if and only if a = 1`。我们可以使用这个技巧来查询指定位上的值。例如 `a & 196` 将会返回 `196`,因为在 `a` 中 `196` 的所有位都被置 1 了。所以我们能够使用 OR 和 AND 来设置和读取配置信息的值。
下面的代码完成了这个功能。函数 `procstr` 转换给定的字符串。它接收两个参数:第一个参数 `str` 是一个要被转换的字符串,第二个参数 `conf` 使用掩码指定转换时的配置信息。
```go
const (
UPPER = 1 // upper case
LOWER = 2 // lower case
CAP = 4 // capitalizes
REV = 8 // reverses
)
func main() {
fmt.Println(procstr("HELLO PEOPLE!", LOWER|REV|CAP))
}
func procstr(str string, conf byte) string {
// reverse string
rev := func(s string) string {
runes := []rune(s)
n := len(runes)
for i := 0; i
runes[i], runes[n-1-i] = runes[n-1-i], runes[i]
}
return string(runes)
}
// query config bits
if (conf & UPPER) != 0 {
str = strings.ToUpper(str)
}
if (conf & LOWER) != 0 {
str = strings.ToLower(str)
}
if (conf & CAP) != 0 {
str = strings.Title(str)
}
if (conf & REV) != 0 {
str = rev(str)
}
return str
}
```
[在线运行](https://play.golang.org/p/4E05PQwj5q)
调用 `procstr("HELLO PEOPLE!", LOWER|REV|CAP)` 将会把字符串转换成小写,反转并将每个单词的首字母转换成大写。当 `conf` 上的第 2、3、4 位为 1 时(conf 等于 14)将会执行上述操作。在内部我们使用 if 语句来取出这些位并且根据相应的配置操作字符串。
## `^` 操作符
XOR 操作符在 Go 中用 `^` 表示。XOR 是特例化的 OR,它有以下特性:
```go
Given operands a, b
XOR(a, b) = 1; only if a != b
else = 0
// 给定 2 个操作数 a,b
// 当且仅当 a!=b 时,操作 XOR(a, b) 返回 1。
// 否者返回 0。
```
这就暗示了我们可以使用 XOR 来切换指定位上的值。例如,给定一个 16 位的值,我们可以使用下面的代码来切换它的前八位:
```go
func main() {
var a uint16 = 0xCEFF
a ^= 0xFF00 // same a = a ^ 0xFF00
}
// a = 0xCEFF (11001110 11111111)
// a ^=0xFF00 (00110001 11111111)
```
在之前的代码中,位的值通过 XOR 操作在 0 和 1 之间切换。XOR 的一个实际的用途就是比较两个数字正负号是否相同。两个数字 `a`、`b`,如果 `(a ^ b) >= 0` 那么 a 和 b 同号,如果 `(a ^ b) <0` 那么 a 和 b 异号。
```go
func main() {
a, b := -12, 25
fmt.Println("a and b have same sign?", (a ^ b) >= 0)
}
```
[在线运行](https://play.golang.org/p/6rAPti5bXJ)
当上述代码执行会输出 `a and b have same sign? false`。使用 Go Playground 可以修改不同的符号查看不同的结果。
### 使用 `^` 作为位非操作
不像其它语言(C/C 、Java、Python、Javascript 等),Go 没有一元运算符。XOR 操作符 `^` 可以作为一元操作符来计算一个数字的补码。给定一个位 `x`,在 Go 中 `^x = 1 ^ x` 将会反转 x 的位。我们可以通过 `^a` 来计算变量 `a` 的补码。
```go
func main() {
var a byte = 0x0F
fmt.Printf("b\n", a)
fmt.Printf("b\n", ^a)
}
// prints
00001111 // var a
11110000 // ^a
```
[在线运行](https://play.golang.org/p/5d1fQjDAIv)
### `&^` 运算符
`&^` 运算符叫做 AND NOT。它是一个 使用 `AND` 后,再使用 `NOT` 操作的简写。该操作符定义如下:
```
Given operands a,b
AND_NOT(a, b) = AND(a, NOT(b))
// 给定两个操作数 a,b
// 当 a=NOT(b)=1 时,操作 AND_NOT(a, b) 返回 1。
// 否则返回 0。
```
它有一个有意思的特性:如果第二个操作符返回 1。那么该位将会被清 0。
```
AND_NOT(a, 1) = 0; clears a
AND_NOT(a, 0) = a;
```
下面这个代码片段使用 AND NOT 操作符来清掉 `a` 的后 4 位(`1010 1011` 到 `1010 0000`)。
```go
func main() {
var a byte = 0xAB
fmt.Printf("b\n", a)
a &^= 0x0F
fmt.Printf("b\n", a)
}
// prints:
10101011
10100000
```
[在线运行](https://play.golang.org/p/UPUlBOPRGh)
## `<<` 和 `>>` 运算符
和其它 C 家族语言一样,Go 使用 `<<` 和 `>>` 来代表左移或者右移运算,定义如下:
```
Given integer operands a and n,
a <
a >> n; 将 a 中的所有位向右偏移 n 次
```
例如:在下面的片段中,`a` 使用左移运算符(`00000011`)左移 3 次。每次的结果都会被打印出来。
```go
func main() {
var a int8 = 3
fmt.Printf("b\n", a)
fmt.Printf("b\n", a<<1)
fmt.Printf("b\n", a<<2)
fmt.Printf("b\n", a<<3)
}
// prints:
00000011
00000110
00001100
00011000
```
需要注意的是,每次左移右边的位都会被 0 填充。相反的,使用右移运算符时左边的位都会被 0 填充(有符号数字除外,具体请看之后的 *Arithmetic Shifts* 章节)。
```go
func main() {
var a uint8 = 120
fmt.Printf("b\n", a)
fmt.Printf("b\n", a>>1)
fmt.Printf("b\n", a>>2)
}
// prints:
01111000
00111100
00011110
```
一些简单的左移和右移的使用技巧就是乘法和除法,其中每次的位移都是乘或者除 2 次幂。下面的代码将 200 除以 2。
```go
func main() {
a := 200
fmt.Printf("%d\n", a>>1)
}
// prints:
100
```
[在线运行](https://play.golang.org/p/EJi0YCARun)
或者将一个值乘 4:
```go
func main() {
a := 12
fmt.Printf("%d\n", a<<2)
}
// prints:
48
```
[在线运行](https://play.golang.org/p/xuJRcKgMVV)
位移运算符提供一种非常有趣的方式来设置一个二进制的值。我们使用 `|` 和 `<<` 来设置 `a` 第三位的值。
```go
func main() {
var a int8 = 8
fmt.Printf("b\n", a)
a = a | (1<<2)
fmt.Printf("b\n", a)
}
// prints:
00001000
00001100
```
[在线运行](https://play.golang.org/p/h7WoP7ieuI)
或者使用 `&` 和位移运算符来测试第 n 位是不是指定的值:
```go
func main() {
var a int8 = 12
if a&(1<<2) != 0 {
fmt.Println("take action")
}
}
// prints:
take action
```
[在线运行](https://play.golang.org/p/Ptc7Txk5Jb)
使用 `&^` 和位移运算来给第 n 位置 0:
```go
func main() {
var a int8 = 13
fmt.Printf("b\n", a)
a = a &^ (1 <<2)
fmt.Printf("b\n", a)
}
// prints:
1101
1001
```
[在线运行](https://play.golang.org/p/Stjq9oOjKz)
### 位移运算符注意事项
当移动的是一个有符号的值,Go 将会自动的适配位移运算。在向右位移时,正负位上的值将会填充在缺失的位上。
go
text
https
git
bit
cpu
编程
main
int
写下你的评论吧 !
吐个槽吧,看都看了
会员登录
|
用户注册
推荐阅读
import
您的环境缺少SentencePiece库,导致XLNetTokenizer无法正常运行
您的环境缺少SentencePiece库,导致XLNetTokenizer无法正常运行 ...
[详细]
蜡笔小新 2024-10-26 15:36:58
import
Spring Boot 中实现多数据源配置:MySQL与Oracle的JDBC集成方案
在 Spring Boot 项目中,实现多数据源配置以支持 MySQL 和 Oracle 数据库的 JDBC 集成。通过合理配置 `application.properties` 文件,可以轻松管理不同数据源的连接属性,确保应用能够高效地访问多种数据库系统。具体配置包括端口设置、字符编码以及数据库连接参数等,为开发者提供了灵活的数据访问解决方案。 ...
[详细]
蜡笔小新 2024-10-26 11:28:36
controller
AngularJS uirouter模块下的状态管理机制深入解析
本文深入探讨了 AngularJS 中 ui-router 模块的状态管理机制。通过详细分析状态配置、状态转换和嵌套状态等核心概念,结合实际案例,帮助开发者更好地理解和应用这一强大工具,提升单页面应用的开发效率和用户体验。 ...
[详细]
蜡笔小新 2024-10-26 03:07:58
php
基于阿里云ECS服务器的k8s集群环境搭建
前言: 网上搭建k8s的文章很多,但很多都无法按其说明在阿里云ecs服务器成功搭建,所以我就花了些时间基于自己成功搭建k8s的步骤写了个操作手册,希望对想搭建k8s环境的盆友有所帮 ...
[详细]
蜡笔小新 2024-10-25 13:19:07
cmd
优化后的标题:在 Asp.net 中动态加载 DropDownList 控件的数据源方法与技巧
在 Asp.net 应用中,动态加载 DropDownList 控件的数据源是一项常见需求。本文探讨了如何高效地从数据库中获取数据,并实时更新下拉列表,确保用户界面始终与后台数据保持同步。通过使用 ADO.NET 和 LINQ to SQL 技术,开发者可以轻松实现这一功能,同时提高应用的性能和用户体验。文中还提供了代码示例和最佳实践,帮助开发者解决常见的数据绑定问题。 ...
[详细]
蜡笔小新 2024-10-24 19:57:15
web
将 Eclipse 中的 Java Web 项目迁移至 IntelliJ IDEA 并配置 Tomcat 环境
为了适应更高效的工作流程,本文详细介绍了如何将基于Eclipse构建的Java Web项目迁移到IntelliJ IDEA,并在新环境中配置Tomcat服务器,以确保项目的顺利运行。此过程不仅涉及项目文件的转移,还包括解决可能遇到的兼容性问题和环境配置挑战。通过本文的指导,开发者可以轻松实现从Eclipse到IntelliJ IDEA的过渡,提升开发效率。 ...
[详细]
蜡笔小新 2024-10-24 17:27:05
client
如何在Maven中高效管理多模块项目中的依赖关系
在Maven中高效管理多模块项目的依赖关系是一项重要的技能。通过合理配置父POM文件,可以统一管理和控制各子模块的依赖版本,避免重复导入和版本冲突。本文将探讨如何利用Maven的最佳实践,确保项目依赖的一致性和可维护性,同时提高开发效率。 ...
[详细]
蜡笔小新 2024-10-24 17:04:44
web
在JavaScript中实现电子邮件和密码的输入验证 - Implementing Input Validation for Email and Password in JavaScript
本文旨在构建一个JavaScript函数,用于对用户输入的电子邮件地址和密码进行有效性验证。该函数将确保输入符合标准格式,并检查密码强度,以提升用户账户的安全性。通过集成正则表达式和条件判断语句,该方法能够有效防止常见的输入错误,同时提供即时反馈,改善用户体验。 ...
[详细]
蜡笔小新 2024-10-24 14:23:11
php
【高效构建全面的iOS直播应用】(美颜功能深度解析)
本文深入探讨了如何高效构建全面的iOS直播应用,特别聚焦于美颜功能的技术实现。通过详细解析美颜算法和优化策略,帮助开发者快速掌握关键技术和实现方法,提升用户体验。适合对直播应用开发感兴趣的开发者阅读。 ...
[详细]
蜡笔小新 2024-10-24 13:52:42
php
Spring Boot与Redis的高效集成方案
本文探讨了Spring Boot与Redis的高效集成方法,详细介绍了如何在Spring Boot项目中配置和使用Redis,以提升应用性能和数据处理能力。同时,文章还涉及了Go语言社区的相关资源,为Golang开发者提供了宝贵的技术交流平台。 ...
[详细]
蜡笔小新 2024-10-26 10:46:12
controller
Spring 中获取 Request 的多种方式及其线程安全性的深入解析
本文深入探讨了在Spring MVC框架下获取HTTP请求对象的多种方法,详细分析了每种方法的实现原理及其线程安全性,为开发者提供了全面的技术参考。 ...
[详细]
蜡笔小新 2024-10-26 08:48:10
controller
通过一张截图深入解析字节跳动的 Java 开发实力
在与一位来自字节跳动的朋友交流时了解到,根据他们近期招聘Java工程师的经验,大多数候选人往往在工作3年后会遇到一个难以跨越的瓶颈期。这是因为在职业生涯的这个阶段,许多工程师的技术深度和广度已经达到了一定的水平,但要进一步提升则需要更多的挑战和学习机会。字节跳动作为一家技术驱动的公司,通过严格的面试流程和实际项目经验,能够更好地评估候选人的技术水平和发展潜力。 ...
[详细]
蜡笔小新 2024-10-25 17:38:05
controller
技术分享:JavaScript博客园鼠标点击动态效果实现笔记
技术分享:JavaScript博客园鼠标点击动态效果实现笔记 ...
[详细]
蜡笔小新 2024-10-24 18:30:09
cmd
在无网络环境下于CentOS 7系统中离线部署Nginx服务器
nginx背景俄罗斯程序员IgorSysoev创建,于2004年NGINX首次发布,来解决C10K问题(10000并发客户端连接到单个服务器,导致服务器连接数过多崩溃的问题),是一 ...
[详细]
蜡笔小新 2024-10-23 19:25:56
web
全球十大热门服务器监控软件
博主通常比较偏爱前端工具,而开发者和设计师则比较关注对站点的处理——他们必须从后端确保那个站点的脚本可以正常运行。有时,出现问题之后很难发现。通常 ...
[详细]
蜡笔小新 2024-10-23 16:41:11
多少年都不会变
这个家伙很懒,什么也没留下!
Tags | 热门标签
command
dagger
runtime
string
grid
jar
rsa
callback
web3
express
instance
frameworks
input
expression
copy
const
php
javascript
web
client
flutter
less
controller
hook
cmd
window
byte
eval
golang
keyword
RankList | 热门文章
1
台式计算机网线插哪里,电脑主机网线插哪里?
2
云计算三种服务模式举例_三种云计算的服务模式,你懂吗?
3
linux bg命令用法,Linux命令常用的一批命令
4
假鸡蛋制作过程(怎么制作假鸡蛋)
5
学会这16个变频器参数设定方法,可以搞定90%变频调试了
6
Docker 容器重新命名
7
linux 服务器无故宕机,请问如何查找原因
8
FPS 游戏飞天遁地原理
9
2020年R1快开门式压力容器操作报名考试及R1快开门式压力容器操作模拟考试题
10
差示光谱法的测定原理_【科普知识】金属复合材料中碳含量的7种测定方法
11
中兴发布第三代5G路由器:速率5.4Gbps 支持NFC一触即连
12
阿里云服务_2021最新阿里云服务器配置表!
13
vim中ctrl+z,jobs,fg命令用法
14
Linux:文件权限数字形式
15
android开发小项目实例_微信小程序开发工具,如何创建一个项目
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有