|
|
@@ -1,2 +1,216 @@
|
|
|
# 结构体,集合和高阶函数
|
|
|
|
|
|
+通常你在应用中定义了一个结构体,那么你也可能需要这个结构体的(指针)对象集合,比如:
|
|
|
+
|
|
|
+```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) {
|
|
|
+ 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
|
|
|
+funcMakeSortedAppender(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(此外只展示了 main() 中的代码,别的代码已经在上面展示)中执行:
|
|
|
+
|
|
|
+示例 11.18 [cars.go](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, 0)
|
|
|
+ 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
|
|
|
+}
|
|
|
+
|
|
|
+/* Output:
|
|
|
+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
|
|
|
+*/
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+## 链接
|
|
|
+
|
|
|
+- [目录](directory.md)
|
|
|
+- 上一节:[Go 中的面向对象](11.13.md)
|
|
|
+- 下一章:[读写数据](12.0.md)
|