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?
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: Difference between some operators "|", "^", "&", "&^". Golang