这方面优点杂,直接放链接
https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md
https://learnku.com/articles/45323
https://blog.youkuaiyun.com/timemachine119/article/details/54927121
第三个链接讲得糊里糊涂的,实际上这个就是值传参和引用传参的老问题,多说无益,我们用一个heap的例子做说明,
一个完整的heap struct 要实现那些方法呢,一共要求实现5个方法才能实现heap接口
type IntHeap []int // 定义一个类型
func (h IntHeap) Len() int { return len(h) } // 绑定len方法,返回长度
func (h IntHeap) Less(i, j int) bool { // 绑定less方法
return h[i] < h[j] // 如果h[i]<h[j]生成的就是小根堆,如果h[i]>h[j]生成的就是大根堆
}
func (h IntHeap) Swap(i, j int) { // 绑定swap方法,交换两个元素位置
h[i], h[j] = h[j], h[i]
}
func (h *IntHeap) Pop() interface{} { // 绑定pop方法,从最后拿出一个元素并返回
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func (h *IntHeap) Push(x interface{}) { // 绑定push方法,插入新元素
*h = append(*h, x.(int))
}
可以看出前三个用的是intHeap,而最后两个用的是*intHeap类型。因为这里用的是切片(type IntHeap []int )对象是引用类型,所以可以直接用intHeap,因为golang提供的sort实际上是基于slice实现的,所以里面必然有引用形式的slice,而后面的heap用 *是一种习惯性质的做法,避免内部的结构体传值传参问题。更复杂的例子:
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string // 姓名
Age int // 年纪
}
type PersonWrapper struct {
people [] Person
by func(p, q * Person) bool
}
func (pw PersonWrapper) Len() int { // 重写 Len() 方法
return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){ // 重写 Swap() 方法
pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool { // 重写 Less() 方法
return pw.by(&pw.people[i], &pw.people[j])
}
func main() {
people := [] Person{
{"zhang san", 12},
{"li si", 30},
{"wang wu", 52},
{"zhao liu", 26},
}
fmt.Println(people)
sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
return q.Age < p.Age // Age 递减排序
}})
fmt.Println(people)
sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
return p.Name < q.Name // Name 递增排序
}})
fmt.Println(people)
}
那么为什么&heap可以调用不管是引用还是值类型的方法呢?
这里就需要提到golang中方法集合的概念,一个struct虽然可以通过值类型和引用类型两种方式定义方法,但是不通的对象类型对应了不同的方法集:
Values Methods Receivers
-----------------------------------------------
T (t T)
*T (t T) and (t *T)
当你的实例是对象的时候只能调用(t T) 结构的方法,而当你的实例是对象指针的时候就可以调用这两种了。