英文:
How to use bit instead of bool in golang structure?
问题
你好!根据你提供的代码,你想将结构体类型的大小从字节转换为位。实际上,Go语言中的结构体字段大小是以字节为单位的,无法直接以位为单位表示。如果你想使用位来表示这些字段,你可以使用位掩码(bitmask)来实现。通过将每个字段映射到一个位,你可以使用位运算来设置和检查每个字段的状态。希望这可以帮助到你!
英文:
type EventPrefs struct {
Call bool
Presence bool
Endpoint bool
VoiceMail bool
CallRecording bool
}
Currently, the size of that struct type is 5 bytes but I would like to use bits. Is there any way to do that?
答案1
得分: 13
在Go语言中没有"bit"类型,所以如果你想将多个bool
信息打包成位(bit),你需要自己实现。声明一个uint8
(或uint16
或其他整数类型)类型的字段,并提供获取/设置字段特定位的方法。
一般的位设置/清除操作如下所示:
var masks = []uint8{0x01, 0x02, 0x04, 0x08, 0x10}
func set(field, data uint8, b bool) uint8 {
if b {
return data | masks[field] // 设置位
}
return data ^ masks[field] // 清除位
}
func get(field, data uint8) bool {
return data&masks[field] != 0
}
将5个bool字段打包到一个uint8
值中:
type EventPrefs struct {
data uint8
}
func (e *EventPrefs) SetCall(b bool) { e.data = set(0, e.data, b) }
func (e *EventPrefs) Call() bool { return get(0, e.data) }
func (e *EventPrefs) SetPresence(b bool) { e.data = set(1, e.data, b) }
func (e *EventPrefs) Presence() bool { return get(1, e.data) }
func (e *EventPrefs) SetEndpoint(b bool) { e.data = set(2, e.data, b) }
func (e *EventPrefs) Endpoint() bool { return get(2, e.data) }
func (e *EventPrefs) SetVoiceMail(b bool) { e.data = set(3, e.data, b) }
func (e *EventPrefs) VoiceMail() bool { return get(3, e.data) }
func (e *EventPrefs) SetCallRecording(b bool) { e.data = set(4, e.data, b) }
func (e *EventPrefs) CallRecording() bool { return get(4, e.data) }
进行测试:
ep := &EventPrefs{}
fmt.Println("Calls:", ep.Call(), ep.data)
ep.SetCall(true)
fmt.Println("Calls:", ep.Call(), ep.data)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(true)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(false)
fmt.Println("Presence:", ep.Presence(), ep.data)
输出结果为:
Calls: false 0
Calls: true 1
Presence: false 1
Presence: true 3
Presence: false 1
是否值得为了节省4个字节而麻烦一番?很少情况下会这样做。
注意:上述解决方案有很多变种。例如,可以使用位移来"计算"掩码,set()
和get()
函数可以成为EventPrefs
的方法,这样就不需要data
参数(set()
可以直接设置EventPrefs.data
字段,因此不需要返回值)。如果set()
仍然是一个函数,data
参数可以是一个指针,这样set()
可以改变指向的值而不返回新的data
等等。data
字段可以有自己声明的类型,例如bitpack
,并附加get()
和set()
方法。
参考链接:https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370
英文:
There is no "bit" type in Go, so if you want to pack multiple bool
information into bits, you have to implement it yourself. Declare a field of type uint8
(or uint16
or any other integer type), and provide methods that get / set specific bits of the field.
General bit setting / clearing is as simple as this:
var masks = []uint8{0x01, 0x02, 0x04, 0x08, 0x10}
func set(field, data uint8, b bool) uint8 {
if b {
return data | masks[field] // Set bit
}
return data ^ masks[field] // Clear bit
}
func get(field, data uint8) bool {
return data&masks[field] != 0
}
Packing your 5 bool fields into an uint8
value:
type EventPrefs struct {
data uint8
}
func (e *EventPrefs) SetCall(b bool) { e.data = set(0, e.data, b) }
func (e *EventPrefs) Call() bool { return get(0, e.data) }
func (e *EventPrefs) SetPresence(b bool) { e.data = set(1, e.data, b) }
func (e *EventPrefs) Presence() bool { return get(1, e.data) }
func (e *EventPrefs) SetEndpoint(b bool) { e.data = set(2, e.data, b) }
func (e *EventPrefs) Endpoint() bool { return get(2, e.data) }
func (e *EventPrefs) SetVoiceMail(b bool) { e.data = set(3, e.data, b) }
func (e *EventPrefs) VoiceMail() bool { return get(3, e.data) }
func (e *EventPrefs) SetCallRecording(b bool) { e.data = set(4, e.data, b) }
func (e *EventPrefs) CallRecording() bool { return get(4, e.data) }
Testing it:
ep := &EventPrefs{}
fmt.Println("Calls:", ep.Call(), ep.data)
ep.SetCall(true)
fmt.Println("Calls:", ep.Call(), ep.data)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(true)
fmt.Println("Presence:", ep.Presence(), ep.data)
ep.SetPresence(false)
fmt.Println("Presence:", ep.Presence(), ep.data)
Which outputs (try it on the Go Playground):
Calls: false 0
Calls: true 1
Presence: false 1
Presence: true 3
Presence: false 1
Is saving 4 bytes worth the hassle? Rarely.
Note: the above solution can have many variations. For example the masks can be "computed" using bitshifts, the set()
and get()
functions could be methods of EventPrefs
and so the data
parameter would not be needed (and set()
could directly set the EventPrefs.data
field so no return value would be needed either). If set()
remains a function, the data
param could be a pointer so set()
could change the pointed value without returning the new data
etc. The data
field may have its own declared type e.g. bitpack
with get()
and set()
methods attached to it.
See related: https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论