php零基础到就业直播视频课:进入学习
程序员必备接口测试调试工具:立即使用
Go 编程语言支持以下按位运算符:
& bitwise AND | bitwise OR ^ bitwise XOR &^ AND NOT << left shift >> right shift
本文的余下部分详述了每个操作符以及它们如何使用的案例。
& 运算符
&ANDAND
Given operands a, b AND(a, b) = 1; only if a = b = 1 else = 0
AND&
func main() { var x uint8 = 0xAC // x = 10101100 x = x & 0xF0 // x = 10100000 }
所有的位运算都支持简写的赋值形式。 例如,前面的例子可以重写为如下。
func main() { var x uint8 = 0xAC // x = 10101100 x &= 0xF0 // x = 10100000 }
&&AND
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) } } }
在 Playground 上运行上面的例子
| 操作符
|或或
Given operands a, b OR(a, b) = 1; when a = 1 or b = 1 else = 0
或或
func main() { var a uint8 = 0 a |= 196 fmt.Printf("%b", a) } // 打印结果 11000100 ^^ ^
练习场中可运行范例。
或a
func main() { var a uint8 = 0 a |= 196 a |= 3 fmt.Printf("%b", a) } // 打印结果 11000111
在练习场中可以运行范例。
或
位运算的配置用法
AND(a, 1) = a 当且仅当 a = 1a & 196aORAND
procstrstrconf
const ( UPPER = 1 // 大写字符串 LOWER = 2 // 小写字符串 CAP = 4 // 字符串单词首字母大写 REV = 8 // 反转字符串 ) func main() { fmt.Println(procstr("HELLO PEOPLE!", LOWER|REV|CAP)) } func procstr(str string, conf byte) string { // 反转字符串 rev := func(s string) string { runes := []rune(s) n := len(runes) for i := 0; i < n/2; i++ { runes[i], runes[n-1-i] = runes[n-1-i], runes[i] } return string(runes) } // 查询配置中的位操作 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 }
在 Playground上面运行代码.
procstr("HELLO PEOPLE!", LOWER|REV|CAP)conf
^ 操作符
异或^异或
Given operands a, b XOR(a, b) = 1; only if a != b else = 0
异或
func main() { var a uint16 = 0xCEFF a ^= 0xFF00 // same a = a ^ 0xFF00 } // a = 0xCEFF (11001110 11111111) // a ^=0xFF00 (00110001 11111111)
异或异或(a ^ b) ≥ 0(a ^ b) < 0true
func main() { a, b := -12, 25 fmt.Println("a and b have same sign?", (a ^ b) >= 0) }
在 Go 的 Playground运行代码。
a and b have same sign? false
^ 作为取反位运算符 (非)
XOR^^aa
func main() { var a byte = 0x0F fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", ^a) } // 打印结果 00001111 // var a 11110000 // ^a
在练习场中可以运行范例。
&^ 操作符
&^与非与非
Given operands a, b AND_NOT(a, b) = AND(a, NOT(b))
如果第二个操作数为 1 那么它则具有清除第一个操作数中的位的趣味特性。
AND_NOT(a, 1) = 0; clears a AND_NOT(a, 0) = a;
AND NOT1010 10111010 0000
func main() { var a byte = 0xAB fmt.Printf("%08b\n", a) a &^= 0x0F fmt.Printf("%08b\n", a) } // 打印: 10101011 10100000
在练习场中运行范例。
<< 和 >> 操作符
<<>>
Given integer operands a and n, a << n; shifts all bits in a to the left n times a >> n; shifts all bits in a to the right n times
a00000011
func main() { var a int8 = 3 fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", a<<1) fmt.Printf("%08b\n", a<<2) fmt.Printf("%08b\n", a<<3) } // 输出的结果: 00000011 00000110 00001100 00011000
在 Playground 运行代码
注意每次移动都会将低位右侧补零。相对应,使用右移位操作符进行运算时,每个位均向右方移动,空出的高位补零,如下示例 (有符号数除外,参考下面的算术移位注释)。
func main() { var a uint8 = 120 fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", a>>1) fmt.Printf("%08b\n", a>>2) } // 打印: 01111000 00111100 00011110
在 练习场中可以运行范例。
200
func main() { a := 200 fmt.Printf("%d\n", a>>1) } // 打印: 100
在 练习场 中可以运行范例。
或是通过左移 2 位,将一个数乘以4:
func main() { a := 12 fmt.Printf("%d\n", a<<2) } // 打印: 48
在 练习场 中可以运行范例。
|<
func main() { var a int8 = 8 fmt.Printf("%08b\n", a) a = a | (1<<2) fmt.Printf("%08b\n", a) } // prints: 00001000 00001100
可以在 练习场 中运行代码示例。
&
func main() { var a int8 = 12 if a&(1<<2) != 0 { fmt.Println("take action") } } // 打印: take action
在 练习场中运行代码。
&^
func main() { var a int8 = 13 fmt.Printf("%04b\n", a) a = a &^ (1 << 2) fmt.Printf("%04b\n", a) } // 打印: 1101 1001
在 练习场 中运行代码。
关于算术位移运算的笔记
当要位移的值(左操作数)是有符号值时,Go 自动应用算术位移。在右移操作期间,复制(或扩展)二进制补码符号位以填充位移的空隙。
总结
与其它现代运算符一样,Go 支持所有二进制位操作运算符。这篇文章仅仅提供了可以用这些操作符完成的各种黑科技示例。你可以在网络上找到很多文章,特别是 Sean Eron Anderson 写的 Bit Twiddling Hacks 。
关注 Vladim @vladimirvivien 的 Twitter。
如果你正在学习 Go,阅读 Vladimir Vivien 关于 Go 的书,名为 Learning Go Programming 。
这篇文章开始由作者 Vladimir Vivien 发布在 Medium 上,名为 Bit Hacking with Go。
更多编程相关知识,请访问:编程视频!!