在 Go 中找不到 BitSet 包,所以我尝试自己实现它。 我希望使用一个 uint64 数组来存储位。
我需要知道要分配的 uint64 数组中的位数。 在 Java 中,我可以定义一个接受整数参数的构造函数。 虽然 Go 没有提供构造函数,但当用户调用 new() 时,我该如何正确地初始化 BitSet '对象' 呢?
在 Go 中找不到 BitSet 包,所以我尝试自己实现它。 我希望使用一个 uint64 数组来存储位。
我需要知道要分配的 uint64 数组中的位数。 在 Java 中,我可以定义一个接受整数参数的构造函数。 虽然 Go 没有提供构造函数,但当用户调用 new() 时,我该如何正确地初始化 BitSet '对象' 呢?
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)
}
}
}
将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) }
}
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
}
append
适用于空切片。它在一个关于append的例子中使用了一个空切片。(为了使这个结论有效,我必须假设Go语言规范中的示例是规范性的,而不是C标准中的。) - Roland Illig简短的回答是,当客户端调用new
()时,你无法正确地初始化BitSet
对象。
最好的方法是使你的BitSet
的零值有效。这就是像list.List
、sync.Mutex
和big.Int
这样的类型所做的。这样你就知道客户端不可能得到一个无效的值。
下一件最好的事情是创建一个类似构造函数的函数(在这种情况下命名为NewBitSet
),并期望客户端调用它。
我也实现了自己的, 它是这样工作的:
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
函数来模拟构造函数。