发布于 

Golang位操作

之前学习语言一直忽略的就是所有语言中关于位操作,觉得用处并不多,可能用到也非常简单的用法,但是其实它们的作用还是非常大的。以下是一些Golang位操作符的基础:

与操作: &

1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

或操作: |

1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

异或: ^

1 ^ 1 = 1
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

左移: <<

1 << 10 = 1024
1 << 20 = 1M
1 << 30 = 1G

右移: >>

1024 >> 10 = 1
1024 >> 1 = 512
1025 >> 2 = 256

关于上述的例子可能在实际的运算中并不是十分的严谨,但是也为我们的业务实现提供了一种思路。

这里拿优酷土豆会员的特权举个例子:

一个优酷账号可以为体验会员、白银会员、黄金会员、酷喵会员…

我们常用的做法就是数据库中存储这个字段表示这个用户开通了哪些特权,如以下代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
"fmt"
)

type users struct {
name string
flag uint8
privilege
}

type privilege struct {
vip bool
experience bool
silver bool
gold bool
cool bool
}

func setVip(user users) users {
user.vip = true
return user
}

func isVip(user users) {
if user.vip {
fmt.Println("user is vip")
} else {
fmt.Println("user is not vip")
}
}

func binaryTest() {
var user users
user.name = "test01"
user.vip = true
isVip(user)
user.vip = false
isVip(user)
}

func main() {
binaryTest()
}

这种实现方式也可以,但是明显我们需要为每个类型都做操作,并且如果以后又有更多的各种各样的会员有需要添加新的,所以并不是最佳方法,下面我们通过位操作来实现上述的功能,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main

import (
"fmt"
)

type users struct {
name string
flag uint8
}

// 通过设置位移的方式默认00000 从左边依次为vip, experience, silver, gold, cool
const (
vip = 1
experience = (1 << 1)
silver = (1 << 2)
gold = (1 << 3)
cool = (1 << 4)
)

// setFlag用户设置用户开通了哪些权限
func setFlag(user users, isSet bool, typeFlag uint8) users {
if isSet == true {
user.flag = user.flag | typeFlag
} else {
user.flag = user.flag ^ typeFlag
}
return user
}

// isFlag 用于判断用户是否开通某项特权
func isFlag(user users, typeFlag uint8) bool {
result := user.flag & typeFlag
return result == typeFlag
}

func binaryTest() {
var user users
user.name = "gopher"
user.flag = 0
// 判断该用户是否为vip
result := isFlag(user, vip)
fmt.Printf("user is Vip: %t\n", result)
// 给用户开通vip, 并查看用户信息里是否已开通
user = setFlag(user, true, vip)
result = isFlag(user, vip)
fmt.Printf("user is Vip: %t\n", result)
// 给用户取消vip, 并查看用户信息里是否还是vip
user = setFlag(user, false, vip)
result = isFlag(user, vip)
fmt.Printf("user is Vip: %t\n", result)
}

func main() {
binaryTest()
}

上面代码一种非常常见的用法,当新添加各种特权的时候只需要在最开始定义的常亮那里添加一行代码即可,就可以直接实现对这种特权的设置和取消,以及查看是否开通。