The GenerateCars function

Here's the actual generator function:

func (cars Collection) GenerateCars(start, limit int) Collection {
carChannel := make(chan *IndexedCar)

The GenerateCars is another method in the cars collection that makes it easy to compose data transformations with other HOFs. GenerateCars takes a start index and limit, which is the number of cars that we want to be returned. We create carChannel of pointers to IndexedCars:

var waitGroup sync.WaitGroup

We use sync.WaitGroup as a counting semaphore to wait for our collection of Goroutines to finish:

numCarsToGenerate := start + limit - 1
generatedCars := Collection{}
waitGroup.Add(numCarsToGenerate)

We calculate the number of cars we want to generate and pass that number to the waitGroup.Add function:

next := carGenerator(iterator, start -1, numCarsToGenerate)

Our carGenerator function returns a function that we assign to a variable named next:

carIndex, done := next()

The next variable returns two variables: carIndex and done. As long as there are more cars to generate, done will be false. So, we can use done to control a for loop that launches a Goroutine, one for each car to generate:

for !done {
go func(carIndex int) {
thisCar, err := GetThisCar(carIndex)
if err != nil {
panic(err)
}
carChannel <- thisCar
generatedCars = append(generatedCars, thisCar.Car)
waitGroup.Done()
}(carIndex)

carIndex, done = next()
}

The next variable returns two variables GetThisCar(carIndex) in the code block; immediately after this, the preceding code calls the RESTful car service that returns the requested car.

If an error is encountered, we use the built-in function panic to stop the execution of the current Goroutine. Since we used a deferred function, namely csvfile.Close(), in the call stack, it will be executed if a panic occurs. Note that we could have had more control over the termination sequence using the built-in recover function.

The thisCar variable is sent to carChannel, and the Car field is appended to the generatedCars collection.