方法值和方法表达式
了解过前面的函数值用法,应该就会使用方法值,在方法值中,接收者对象成为了引用环境中的参数变量。比如:
func (p Person) GetName() string {
return p.Name
}
func main(){
var per = Person{Name: "chendonghai"}
peronFunc := per.GetName
fmt.Println(personFunc()) // chendonghai
}
// 10s后执行personFunc对象
time.AfterFunc(10 * time.Second, personFunc)
在写完Go圣经-学习笔记系列文章后,我们就会开始进入学习雨痕老师的Go语言源码分析,我们到时候再来剖析这个引用环境,现在直接告诉读者,接受者数据对象作为第一个实参存放。我们通过方法表达式验证一下。
type Person struct {
Name string
}
func (p Person) Love(q Person) {
fmt.Printf("%s love %s.\n", p.Name, q.Name)
}
func main() {
var p = Person{
Name: "Jacky",
}
var q = Person{
Name: "Rose",
}
method:= Person.Love
method(q, p) // Rose love Jacky.
method(p, q) // Jacky love Rose.
}
当方法或者函数类型相同时,如果需要根据其他外部环境,决定使用某个方法或者函数时,那么表达式就非常具有实用性。
type func Operation(p Point, q Point) Point
type Path []Point
func (path Path) TranslateBy(offset Point, add bool) {
if add {
Operation = Point.Add
} else {
Operation = Point.Sub
}
for i:= range path {
path[i] = Operation(path[i], offset)
}
}
Bit数组
Go语言里的集合,我们前面说过,用map比较简单合适。形式:map[Type]bool或者map[Type]struct{}
,后者更节省空间,但是用起来不太方便struct{}{}
。如果要进行集合的运算,包括:交集、并集、差集等,我们可以用一种更加合适的方式表达集合元素,Bit数组。
一个Bit数组通常会用一个无符号的或者称之为“字”的slice动态数组表示,每一个元素的每一位都表示集合里的一个元素值。当集合的第i
位被设置时,我们就说这个集合包含元素i。
因为要举一个例子,所以为了方便用户理解,我来简单说明一下,上面的具体含义:
/*
如果查看集合中是否有8这个值,我们用uint64数据类型表示:0000...0000(64个0)。如果低位第八位是1,
则表示集合含有这个元素8。但是uint64数据类型的数据空间长度只有64位,只能表示非负整数,且数值范围1~64,
大于64的元素值无法表示,这就需要引入slice动态数据表示
这样说不知道读者是否理解,如果理解,下面这个DEMO就容易明白。当然这很浪费空间,
因为如果是稀疏数据的话,严重浪费空间。先不管这些,这要考虑到压缩,或者编码问题。
*/
type IntSet struct {
words []uint64
}
func (s *IntSet) Has(x int) bool {
word, bit := x/64, uint(x%64) // 第一个:第几个数组元素,第二个:这个元素的第几位
return word < len(s.words) && s.words[word]&(1<<bit) != 0
}
func (s *IntSet) Add(x int) {
word, bit := x/64, x%64
for word >= len(s.words) {
s.words = append(s.words, 0)
}
s.words[word] |= 1 << uint(bit) // 位或
}
// 并集
func (s *IntSet) Union(t *IntSet) {
for i, tword := range t.words {
if i < len(s.words) {
s.words[i] |= tword
} else {
s.words = append(s.words, tword)
}
}
return
}
// 打印集合
func (s *IntSet) String() string {
var buffer bytes.Buffer
buffer.WriteString("{")
for i, word := range s.words {
for j := 0; j < 64; j++ {
if word&(1<<uint(j)) != 0 {
fmt.Fprintf(&buffer, "%d,", i*64+j)
}
}
}
buffer.WriteString("}")
return buffer.String()
}
func main() {
var set = &IntSet{}
var words = []uint64{1, 4, 8, 2, 49, 23, 16, 27, 28, 29}
for _, word := range words {
set.Add(int(word))
}
fmt.Println(set.String())
}