英文:
How to implement BitSet with Go?
问题
我在Go语言中没有找到BitSet包,所以我尝试自己实现它。
我想使用一个uint64数组来存储位。
我需要知道位数以分配uint64数组的大小。
在Java中,我可以定义一个构造函数来接受一个整数。
而Go语言没有提供构造函数,当用户调用new()时,我该如何正确初始化BitSet '对象'呢?
英文:
I didn't find a BitSet package in Go, so I tried to implement it.
I'd like to use a array of uint64 to store the bits.
I need the number of bits to allocate the uint64 array.
With Java, I can define a constructor that takes an integer.
While Go doesn't provide constructor, how can I properly initialize
the BitSet 'object' when user call new()?
答案1
得分: 16
Go的标准库big.Int
可以用作位集合:
package main
import (
"fmt"
"math/big"
)
func main() {
var bits big.Int
for i := 1000; i < 2000; i++ {
bits.SetBit(&bits, i, 1)
}
for i := 0; i < 10000; i++ {
if bits.Bit(i) != 0 {
fmt.Println(i)
}
}
}
https://play.golang.org/p/xbIK-boouqC
英文:
Go's standard big.Int
can be used as a bit set:
package main
import (
"fmt"
"math/big"
)
func main() {
var bits big.Int
for i := 1000; i < 2000; i++ {
bits.SetBit(&bits, i, 1)
}
for i := 0; i < 10000; i++ {
if bits.Bit(i) != 0 {
fmt.Println(i)
}
}
}
答案2
得分: 5
声明bitSet为一个私有结构体:
type bitSet struct {
len int
array []uint64
}
暴露BitSet接口:
type BitSet interface {
Has(pos int) bool
Add(pos int) bool
Len() int
}
同时暴露一个NewBitSet函数:
func NewBitSet(len int) BitSet {
return &bitSet{len, make([]uint64, (len+7) / 8) }
}
这是Go语言中封装的一种方式:共享接口,而不是实现。
英文:
Declare bitSet as a private struct:
type bitSet struct {
len int
array []uint64
}
Expose the interface BitSet:
type BitSet interface {
Has(pos int) bool
Add(pos int) bool
Len() int
}
Also expose a function NewBitSet:
func NewBitSet(len int) BitSet {
return &bitSet{len, make(uint64, (len+7) / 8) }
}
This is a Go way for encapsulation: share an interface, not the implementation.
答案3
得分: 3
如果您使用一个 []uint64 切片来存储数据,那么零切片可以作为空的 BitSet。实际上,向一个空切片追加元素会为您分配一个新的数组,尽管语言规范似乎并没有保证这一点。有了这样的设置,new(BitSet) 就可以立即使用。示例:
bitset.go:
package bitset
const size = 64
type bits uint64
// BitSet 是一个可以设置、清除和查询的位集合。
type BitSet []bits
// Set 确保 BitSet 中的给定位被设置。
func (s *BitSet) Set(i uint) {
if len(*s) < int(i/size+1) {
r := make([]bits, i/size+1)
copy(r, *s)
*s = r
}
(*s)[i/size] |= 1 << (i % size)
}
// Clear 确保 BitSet 中的给定位被清除(未设置)。
func (s *BitSet) Clear(i uint) {
if len(*s) >= int(i/size+1) {
(*s)[i/size] &^= 1 << (i % size)
}
}
// IsSet 如果给定位被设置,则返回 true,如果被清除,则返回 false。
func (s *BitSet) IsSet(i uint) bool {
return (*s)[i/size]&(1<<(i%size)) != 0
}
bitset_test.go:
package bitset
import "fmt"
func ExampleBitSet() {
s := new(BitSet)
s.Set(13)
s.Set(45)
s.Clear(13)
fmt.Printf("s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n",
s.IsSet(13), s.IsSet(45), s.IsSet(30))
// Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}
英文:
If you use a []uint64 slice to store your data, then the zero slice could function as the empty BitSet. In fact appending to a nil slice allocates a new array for you, although the Language Specification doesn't appear to guarantee that. With that kind of setup, new(BitSet) would be immediately usable. Example:
bitset.go:
package bitset
const size = 64
type bits uint64
// BitSet is a set of bits that can be set, cleared and queried.
type BitSet []bits
// Set ensures that the given bit is set in the BitSet.
func (s *BitSet) Set(i uint) {
if len(*s) < int(i/size+1) {
r := make([]bits, i/size+1)
copy(r, *s)
*s = r
}
(*s)[i/size] |= 1 << (i % size)
}
// Clear ensures that the given bit is cleared (not set) in the BitSet.
func (s *BitSet) Clear(i uint) {
if len(*s) >= int(i/size+1) {
(*s)[i/size] &^= 1 << (i % size)
}
}
// IsSet returns true if the given bit is set, false if it is cleared.
func (s *BitSet) IsSet(i uint) bool {
return (*s)[i/size]&(1<<(i%size)) != 0
}
bitset_test.go:
package bitset
import "fmt"
func ExampleBitSet() {
s := new(BitSet)
s.Set(13)
s.Set(45)
s.Clear(13)
fmt.Printf("s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n",
s.IsSet(13), s.IsSet(45), s.IsSet(30))
// Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}
答案4
得分: 1
简短的回答是,当客户端调用new
()时,无法正确初始化BitSet
对象。
你能做的最好的事情是确保你的BitSet
的零值是有效的。这就是像list.List
、sync.Mutex
和big.Int
这样的类型所做的。这样你就知道客户端不可能得到一个无效的值。
你能做的下一件最好的事情是创建一个类似构造函数的函数(在这种情况下命名为NewBitSet
),并期望客户端调用它。
英文:
The short answer is, you can't properly initialize the BitSet
object when a client calls new
().
The best thing you can do is make it so that your BitSet
's zero value is valid. This is what types like list.List
, sync.Mutex
, and big.Int
do. This way you know that it's impossible for a client to get an invalid value.
The next best thing you can do is create a constuctor-like function (named NewBitSet
in this case) and expect clients to call it.
答案5
得分: 0
我也实现了自己的,它是这样工作的:
bm := bitmask.New(4) // [4]{0000}
bm.Set(3) // [4]{0001}
bm.Slice(2, 4).ToggleAll() // [4]{0010}
bm.Slice(1, 3).ToggleAll() // [4]{0100}
bm.Slice(0, 2).ToggleAll() // [4]{1000}
bm.Clear() // [4]{0000}
正如其他人所回答的,有一个惯例使用New
函数来模拟构造函数。
英文:
I've implemented my own too, and that's how It works:
bm := bitmask.New(4) // [4]{0000}
bm.Set(3) // [4]{0001}
bm.Slice(2, 4).ToggleAll() // [4]{0010}
bm.Slice(1, 3).ToggleAll() // [4]{0100}
bm.Slice(0, 2).ToggleAll() // [4]{1000}
bm.Clear() // [4]{0000}
As others have answered, there's a convention to use New
function to mimic the constructor.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论