> For the complete documentation index, see [llms.txt](https://ryanyang.gitbook.io/the-way-to-go-zh-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryanyang.gitbook.io/the-way-to-go-zh-cn/di-er-bu-fen-yu-yan-de-he-xin-jie-gou-yu-ji-shu/11.0/11.14.md).

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

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

```go
type Any interface{}
type Car struct {
    Model        string
    Manufacturer string
    BuildYear    int
    // ...
}

type Cars []*Car
```

在定义所需功能时我们可以利用函数可以作为（其它函数的）参数的事实来使用高阶函数，例如：

1）定义一个通用的 `Process()` 函数，它接收一个作用于每一辆 car 的 f 函数作参数：

```go
// Process all cars with the given function f:
func (cs Cars) Process(f func(car *Car)) {
    for _, c := range cs {
        f(c)
    }
}
```

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

```go
// Find all cars matching a given criteria.
func (cs Cars) FindAll(f func(car *Car) bool) Cars {

    cars := make([]*Car, 0)
    cs.Process(func(c *Car) {
        if f(c) {
            cars = append(cars, c)
        }
    })
    return cars
}
```

3）实现 Map 功能，产出除 car 对象以外的东西：

```go
// Process cars and create new data.
func (cs Cars) Map(f func(car *Car) Any) []Any {
    result := make([]Any, 0)
    ix := 0
    cs.Process(func(c *Car) {
        result[ix] = f(c)
        ix++
    })
    return result
}
```

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

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

4）我们也可以根据入参返回不同的函数。也许我们想根据不同的厂商添加汽车到不同的集合，但是这可能会是多变的。所以我们可以定义一个函数来产生特定的添加函数和 map 集：

```go
func MakeSortedAppender(manufacturers[]string)(func(car*Car),map[string]Cars) {
    // Prepare maps of sorted cars.
    sortedCars := make(map[string]Cars)
    for _, m := range manufacturers {
        sortedCars[m] = make([]*Car, 0)
    }
    sortedCars["Default"] = make([]*Car, 0)
    // Prepare appender function:
    appender := func(c *Car) {
        if _, ok := sortedCars[c.Manufacturer]; ok {
            sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)
        } else {
            sortedCars["Default"] = append(sortedCars["Default"], c)
        }

    }
    return appender, sortedCars
}
```

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

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

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

示例 11.18 [cars.go](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/examples/chapter_11/cars.go)：

```go
// cars.go
package main

import (
    "fmt"
)

type Any interface{}
type Car struct {
    Model        string
    Manufacturer string
    BuildYear    int
    // ...
}
type Cars []*Car

func main() {
    // make some cars:
    ford := &Car{"Fiesta", "Ford", 2008}
    bmw := &Car{"XL 450", "BMW", 2011}
    merc := &Car{"D600", "Mercedes", 2009}
    bmw2 := &Car{"X 800", "BMW", 2008}
    // query:
    allCars := Cars([]*Car{ford, bmw, merc, bmw2})
    allNewBMWs := allCars.FindAll(func(car *Car) bool {
        return (car.Manufacturer == "BMW") && (car.BuildYear > 2010)
    })
    fmt.Println("AllCars: ", allCars)
    fmt.Println("New BMWs: ", allNewBMWs)
    //
    manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jaguar"}
    sortedAppender, sortedCars := MakeSortedAppender(manufacturers)
    allCars.Process(sortedAppender)
    fmt.Println("Map sortedCars: ", sortedCars)
    BMWCount := len(sortedCars["BMW"])
    fmt.Println("We have ", BMWCount, " BMWs")
}

// Process all cars with the given function f:
func (cs Cars) Process(f func(car *Car)) {
    for _, c := range cs {
        f(c)
    }
}

// Find all cars matching a given criteria.
func (cs Cars) FindAll(f func(car *Car) bool) Cars {
    cars := make([]*Car, 0)

    cs.Process(func(c *Car) {
        if f(c) {
            cars = append(cars, c)
        }
    })
    return cars
}

// Process cars and create new data.
func (cs Cars) Map(f func(car *Car) Any) []Any {
    result := make([]Any, len(cs))
    ix := 0
    cs.Process(func(c *Car) {
        result[ix] = f(c)
        ix++
    })
    return result
}

func MakeSortedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {
    // Prepare maps of sorted cars.
    sortedCars := make(map[string]Cars)

    for _, m := range manufacturers {
        sortedCars[m] = make([]*Car, 0)
    }
    sortedCars["Default"] = make([]*Car, 0)

    // Prepare appender function:
    appender := func(c *Car) {
        if _, ok := sortedCars[c.Manufacturer]; ok {
            sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)
        } else {
            sortedCars["Default"] = append(sortedCars["Default"], c)
        }
    }
    return appender, sortedCars
}
```

输出：

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

## 链接

* [目录](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/directory.md)
* 上一节：[Go 中的面向对象](/the-way-to-go-zh-cn/di-er-bu-fen-yu-yan-de-he-xin-jie-gou-yu-ji-shu/11.0/11.13.md)
* 下一章：[读写数据](/the-way-to-go-zh-cn/di-san-bu-fen-go-gao-ji-bian-cheng/12.0.md)
