Go圣经-学习笔记之方法值和表达式

上一篇 Go圣经-学习笔记之封装还是组合

下一篇 Go圣经-学习笔记之接口

方法值和方法表达式

了解过前面的函数值用法,应该就会使用方法值,在方法值中,接收者对象成为了引用环境中的参数变量。比如:

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())
}

转载于:https://my.oschina.net/u/3287304/blog/1557199

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值