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

    结构体、集合和高阶函数

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

    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 功能,产出除 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