writing generic algorithm

在 Golang 中并不支持泛型编程。在 C++ 等高级语言中使用泛型编程非常的简单,所以泛型编程一直是 Golang 诟病最多的地方。 但是使用 interface 我们可以实现泛型编程,我这里简单说一下,具体可以参考我前面给出来的那篇文章。比如我们现在要写一个泛型算法, 形参定义采用 interface 就可以了,以标准库的 sort 为例。

  1. package sort
  2. // A type, typically a collection, that satisfies sort.Interface can be
  3. // sorted by the routines in this package. The methods require that the
  4. // elements of the collection be enumerated by an integer index.
  5. type Interface interface {
  6. // Len is the number of elements in the collection.
  7. Len() int
  8. // Less reports whether the element with
  9. // index i should sort before the element with index j.
  10. Less(i, j int) bool
  11. // Swap swaps the elements with indexes i and j.
  12. Swap(i, j int)
  13. }
  14. ...
  15. // Sort sorts data.
  16. // It makes one call to data.Len to determine n, and O(n*log(n)) calls to
  17. // data.Less and data.Swap. The sort is not guaranteed to be stable.
  18. func Sort(data Interface) {
  19. // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
  20. n := data.Len()
  21. maxDepth := 0
  22. for i := n; i > 0; i >>= 1 {
  23. maxDepth++
  24. }
  25. maxDepth *= 2
  26. quickSort(data, 0, n, maxDepth)
  27. }

Sort 函数的形参是一个 interface,包含了三个方法:Len(),Less(i,j int),Swap(i, j int)。 使用的时候不管数组的元素类型是什么类型(int, float, string…),只要我们实现了这三个方法就可以使用 Sort 函数,这样就实现了“泛型编程”。 有一点比较麻烦的是,我们需要将数组自定义一下。下面是一个例子。

  1. type Person struct {
  2. Name string
  3. Age int
  4. }
  5. func (p Person) String() string {
  6. return fmt.Sprintf("%s: %d", p.Name, p.Age)
  7. }
  8. // ByAge implements sort.Interface for []Person based on
  9. // the Age field.
  10. type ByAge []Person //自定义
  11. func (a ByAge) Len() int { return len(a) }
  12. func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  13. func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
  14. func main() {
  15. people := []Person{
  16. {"Bob", 31},
  17. {"John", 42},
  18. {"Michael", 17},
  19. {"Jenny", 26},
  20. }
  21. fmt.Println(people)
  22. sort.Sort(ByAge(people))
  23. fmt.Println(people)
  24. }