Structs, Collections and Higher-Order Functions
This lesson is an implementation of the example that covers the concepts of structs, interfaces, and higher-order functions studied so far.
Often, when you have a struct in your application, you also need a collection of (pointers to) objects of that struct, like:
type Any interface{}
type Car struct {
Model string
Manufacturer string
BuildYear int
// ...
}
type Cars []*Car
We can then use the fact that higher-order functions can be arguments to other functions when defining the needed functionality, e.g.:
- When defining a general
Process()
function, which itself takes a functionf
which operates on every car:
// Process all cars with the given function f:
func (cs Cars) Process(f func(car *Car)) {
for _, c := range cs {
f(c)
}
}
- Building upon this, make Find-functions to obtain subsets, and call
Process()
with a closure (so it knows the local slice cars):
// Find all cars matching 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
}
- And make a Map-functionality producing something out of every car object:
// 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
}
Now, we can define concrete queries like:
allNewBMWs := allCars.FindAll(func(car *Car) bool {
return (car.Manufacturer == "BMW") && (car.BuildYear > 2010)
})
- We can also return functions based on arguments. Maybe we would like to append cars to collections based on the manufacturers, but those may be varying. So, we define a function to create a special append function as well as a map of collections:
func MakeGroupedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {
// Prepare maps for grouping the cars.
groupedCars := make(map[string]Cars)
for _, m := range manufacturers {
groupedCars[m] = make([]*Car, 0)
}
groupedCars["Default"] = make([]*Car, 0)
// Prepare appender function:
appender := func(c *Car) {
if _, ok := groupedCars[c.Manufacturer]; ok {
groupedCars[c.Manufacturer] = append(groupedCars[c.Manufacturer], c)
} else {
groupedCars["Default"] = append(groupedCars["Default"], c)
}
}
return appender, groupedCars
}
We now can use it to sort our cars into individual collections, like in:
manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jaguar"}
groupedAppender, sortedCars := MakeGroupedAppender(manufacturers)
allUngroupedCars.Process(groupedAppender)
BMWCount := len(groupedCars["BMW"])
Now that you are familiar with a lot of concepts related to interfaces, the next lesson brings you a challenge to solve.
Get hands-on with 1400+ tech skills courses.