Kotlin中Grid类实现Iterable<Cell>:简化扁平化遍历方案
I have a Grid class that wraps a 2D array of Cell objects. I want this class to implement the Iterable
interface so that I can directly iterate over all Cell objects in loops. Is there a simple implementation method? Does Kotlin support yield return-style iterators? My current implementation is very verbose, the code is as follows: | override fun iterator() = object : Iterator<Cell> { val currentOuter = grid.iterator() // grid is object of Array<Array<Cell>> var currentInner = if (currentOuter.hasNext()) currentOuter.next().iterator() else arrayOf<Cell>().iterator() override fun next(): Cell { if (!hasNext()) { throw NoSuchElementException() } return if (currentInner.hasNext()) { currentInner.next() } else { currentInner = currentOuter.next().iterator() currentInner.next() } } override fun hasNext(): Boolean { return currentInner.hasNext() || currentOuter.hasNext() } }
Great question! Kotlin absolutely supports yield-style iterators, and there are far more concise ways to implement Iterable<Cell> for your Grid class than the manual iterator you wrote. Let's break down the best options:
1. Super simple (with intermediate list)
If you don't mind a temporary list being created to hold all cells (perfectly fine for most small-to-medium grids), you can use Kotlin's built-in flatten() function to convert the 2D array to a 1D list, then return its iterator directly:
class Grid(private val grid: Array<Array<Cell>>) : Iterable<Cell> { override fun iterator(): Iterator<Cell> { return grid.flatten().iterator() } }
This cuts your implementation down to one line inside iterator(), and it's immediately readable. The only minor downside is the intermediate list—if your grid is extremely large, this could use extra memory unnecessarily.
2. Yield-style iterator (memory efficient, no intermediate list)
For a memory-efficient solution that matches the "yield return" style you asked about, Kotlin has a built-in iterator higher-order function (from the kotlin.collections package) that handles all the state management for you. You can use yieldAll() to emit entire rows of cells, or yield() for individual elements if you need custom traversal logic:
class Grid(private val grid: Array<Array<Cell>>) : Iterable<Cell> { override fun iterator(): Iterator<Cell> = iterator { // Iterate over each row, and emit all its cells for (row in grid) { yieldAll(row) } } }
This implementation creates no intermediate lists—it generates cells on-the-fly as the iterator is consumed. Under the hood, Kotlin converts this lambda into a state machine that automatically handles the hasNext() and next() logic, replacing all that verbose boilerplate you wrote earlier.
If you ever need to adjust the traversal order (like iterating column-by-column instead of row-by-row), it's trivial to modify with yield:
override fun iterator(): Iterator<Cell> = iterator { val rowCount = grid.size if (rowCount == 0) return@iterator val colCount = grid[0].size // Iterate column by column for (col in 0 until colCount) { for (row in 0 until rowCount) { yield(grid[row][col]) } } }
This approach is clean, flexible, and eliminates all the error-prone manual iterator code.
内容的提问来源于stack exchange,提问作者Konrad

