11.14 结构体、集合和高阶函数

通常你在应用中定义了一个结构体,那么你也可能需要这个结构体的(指针)对象集合,比如:

  1. type Any interface{}
  2. type Car struct {
  3. Model string
  4. Manufacturer string
  5. BuildYear int
  6. // ...
  7. }
  8. type Cars []*Car

然后我们就可以使用高阶函数,实际上也就是把函数作为定义所需方法(其他函数)的参数,例如:

1)定义一个通用的 Process() 函数,它接收一个作用于每一辆 car 的 f 函数作参数:

  1. // Process all cars with the given function f:
  2. func (cs Cars) Process(f func(car *Car)) {
  3. for _, c := range cs {
  4. f(c)
  5. }
  6. }

2)在上面的基础上,实现一个查找函数来获取子集合,并在 Process() 中传入一个闭包执行(这样就可以访问局部切片 cars):

  1. // Find all cars matching a given criteria.
  2. func (cs Cars) FindAll(f func(car *Car) bool) Cars {
  3. cars := make([]*Car, 0)
  4. cs.Process(func(c *Car) {
  5. if f(c) {
  6. cars = append(cars, c)
  7. }
  8. })
  9. return cars
  10. }

3)实现对应作用的功效 (Map-functionality),从每个 car 对象当中产出某些东西:

  1. // Process cars and create new data.
  2. func (cs Cars) Map(f func(car *Car) Any) []Any {
  3. result := make([]Any, 0)
  4. ix := 0
  5. cs.Process(func(c *Car) {
  6. result[ix] = f(c)
  7. ix++
  8. })
  9. return result
  10. }

现在我们可以定义下面这样的具体查询:

  1. allNewBMWs := allCars.FindAll(func(car *Car) bool {
  2. return (car.Manufacturer == "BMW") && (car.BuildYear > 2010)
  3. })

4)我们也可以根据参数返回不同的函数。也许我们想根据不同的厂商添加汽车到不同的集合,但是这(这种映射关系)可能会是会改变的。所以我们可以定义一个函数来产生特定的添加函数和 map 集:

  1. func MakeSortedAppender(manufacturers []string)(func(car *Car),map[string]Cars) {
  2. // Prepare maps of sorted cars.
  3. sortedCars := make(map[string]Cars)
  4. for _, m := range manufacturers {
  5. sortedCars[m] = make([]*Car, 0)
  6. }
  7. sortedCars["Default"] = make([]*Car, 0)
  8. // Prepare appender function:
  9. appender := func(c *Car) {
  10. if _, ok := sortedCars[c.Manufacturer]; ok {
  11. sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)
  12. } else {
  13. sortedCars["Default"] = append(sortedCars["Default"], c)
  14. }
  15. }
  16. return appender, sortedCars
  17. }

现在我们可以用它把汽车分类为独立的集合,像这样:

  1. manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jaguar"}
  2. sortedAppender, sortedCars := MakeSortedAppender(manufacturers)
  3. allUnsortedCars.Process(sortedAppender)
  4. BMWCount := len(sortedCars["BMW"])

我们让这些代码在下面的程序 cars.go 中执行:

示例 11.18 cars.go

  1. // cars.go
  2. package main
  3. import (
  4. "fmt"
  5. )
  6. type Any interface{}
  7. type Car struct {
  8. Model string
  9. Manufacturer string
  10. BuildYear int
  11. // ...
  12. }
  13. type Cars []*Car
  14. func main() {
  15. // make some cars:
  16. ford := &Car{"Fiesta", "Ford", 2008}
  17. bmw := &Car{"XL 450", "BMW", 2011}
  18. merc := &Car{"D600", "Mercedes", 2009}
  19. bmw2 := &Car{"X 800", "BMW", 2008}
  20. // query:
  21. allCars := Cars([]*Car{ford, bmw, merc, bmw2})
  22. allNewBMWs := allCars.FindAll(func(car *Car) bool {
  23. return (car.Manufacturer == "BMW") && (car.BuildYear > 2010)
  24. })
  25. fmt.Println("AllCars: ", allCars)
  26. fmt.Println("New BMWs: ", allNewBMWs)
  27. //
  28. manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jaguar"}
  29. sortedAppender, sortedCars := MakeSortedAppender(manufacturers)
  30. allCars.Process(sortedAppender)
  31. fmt.Println("Map sortedCars: ", sortedCars)
  32. BMWCount := len(sortedCars["BMW"])
  33. fmt.Println("We have ", BMWCount, " BMWs")
  34. }
  35. // Process all cars with the given function f:
  36. func (cs Cars) Process(f func(car *Car)) {
  37. for _, c := range cs {
  38. f(c)
  39. }
  40. }
  41. // Find all cars matching a given criteria.
  42. func (cs Cars) FindAll(f func(car *Car) bool) Cars {
  43. cars := make([]*Car, 0)
  44. cs.Process(func(c *Car) {
  45. if f(c) {
  46. cars = append(cars, c)
  47. }
  48. })
  49. return cars
  50. }
  51. // Process cars and create new data.
  52. func (cs Cars) Map(f func(car *Car) Any) []Any {
  53. result := make([]Any, len(cs))
  54. ix := 0
  55. cs.Process(func(c *Car) {
  56. result[ix] = f(c)
  57. ix++
  58. })
  59. return result
  60. }
  61. func MakeSortedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {
  62. // Prepare maps of sorted cars.
  63. sortedCars := make(map[string]Cars)
  64. for _, m := range manufacturers {
  65. sortedCars[m] = make([]*Car, 0)
  66. }
  67. sortedCars["Default"] = make([]*Car, 0)
  68. // Prepare appender function:
  69. appender := func(c *Car) {
  70. if _, ok := sortedCars[c.Manufacturer]; ok {
  71. sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)
  72. } else {
  73. sortedCars["Default"] = append(sortedCars["Default"], c)
  74. }
  75. }
  76. return appender, sortedCars
  77. }

输出:

  1. AllCars: [0xf8400038a0 0xf840003bd0 0xf840003ba0 0xf840003b70]
  2. New BMWs: [0xf840003bd0]
  3. Map sortedCars: map[Default:[0xf840003ba0] Jaguar:[] Land Rover:[] BMW:[0xf840003bd0 0xf840003b70] Aston Martin:[] Ford:[0xf8400038a0]]
  4. We have 2 BMWs

链接