menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right the-way-to-go_ZH_CN chevron_right eBook chevron_right 11.14.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    11.14.md
    5.33 KB / 2024-07-16 23:14:27
        # 11.14 结构体、集合和高阶函数
    
    通常你在应用中定义了一个结构体,那么你也可能需要这个结构体的(指针)对象集合,比如:
    
    ```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-functionality),从每个 `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](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
    ```
    
    
    ## 链接
    
    - [目录](directory.md)
    - 上一节:[Go 中的面向对象](11.13.md)
    - 下一章:[读写数据](12.0.md)
    
    
    links
    file_download