Scala中如何实现Iterator重复迭代?游戏开发场景需求
Great question—using Iterators for repeated player loops in games is a smart call, especially when you want lazy evaluation (no precomputing all players upfront) and flexible control over iteration state. Let’s break down simple, practical implementations for your use case:
1. Infinite Looping Iterator (for endless player cycles)
If you need to cycle through players indefinitely (like in a game where turns repeat until a win condition is met), use Iterator.continually combined with flatten to wrap your player collection. This creates an iterator that never runs out—each call to next() will loop back to the first player after the last one.
case class Player(name: String) val players = List(Player("Alice"), Player("Bob"), Player("Charlie")) // Infinite iterator that cycles through players val infinitePlayerIterator: Iterator[Player] = Iterator.continually(players).flatten // Example usage: Simulate 5 consecutive turns for (_ <- 1 to 5) { val currentPlayer = infinitePlayerIterator.next() println(s"${currentPlayer.name} takes their turn!") }
Output:
Alice takes their turn! Bob takes their turn! Charlie takes their turn! Alice takes their turn! Bob takes their turn!
For this iterator:
hasDefiniteSizereturnsfalse(since it’s infinite)isTraversableAgainreturnstrue(you can keep callingnext()forever without needing to reset)
2. Resettable Finite Iterator (for controlled repeats)
If you want a finite iterator that can be reset to start over (instead of infinite looping), implement a custom iterator that wraps your source collection. This lets you manually or automatically reset the iteration when you reach the end.
class ResettableIterator[A](private val source: Iterable[A]) extends Iterator[A] { private var currentIterator = source.iterator // Reset to start when we hit the end, then check for elements override def hasNext: Boolean = { if (!currentIterator.hasNext) { currentIterator = source.iterator // Reset to beginning false // Return false to stop at the end; return true to loop immediately } currentIterator.hasNext } override def next(): A = { if (!hasNext) throw new NoSuchElementException("No more players to iterate over") currentIterator.next() } // Explicit reset method for manual control def reset(): Unit = currentIterator = source.iterator // Mark this iterator as reusable override def isTraversableAgain: Boolean = true }
Usage Example:
val resettablePlayers = new ResettableIterator(players) // First pass through players while (resettablePlayers.hasNext) { println(s"${resettablePlayers.next().name} plays!") } // Reset and iterate again for a new round resettablePlayers.reset() println("\n--- New round starts ---") while (resettablePlayers.hasNext) { println(s"${resettablePlayers.next().name} plays!") }
3. Simplest Approach: Reuse Iterable’s Iterator
If you don’t need to maintain a single iterator instance (e.g., you just need to loop through players from the start each round), the easiest solution is to call iterator() on your player collection every time you need a fresh iteration. Most Scala collections (like List, Vector) are Iterable, so they generate a new iterator each time:
// For each game round, get a fresh iterator def startGameRound(): Unit = { val playerIterator = players.iterator println("\n--- Starting new round ---") while (playerIterator.hasNext) { val player = playerIterator.next() // Execute player turn logic here println(s"${player.name}'s turn!") } } // Call this as many times as needed for new rounds startGameRound() startGameRound()
This approach avoids custom code and leverages Scala’s built-in collection behavior. For the iterators created this way:
hasDefiniteSizereturnstrue(since the source collection is finite)isTraversableAgainreturnsfalsefor the individual iterator instance (but you just create a new one each time)
Key Notes on hasDefiniteSize and isTraversableAgain
hasDefiniteSize: Tells you if the iterator has a fixed, known length. Infinite iterators returnfalse; finite ones returntrue.isTraversableAgain: Indicates whether you can iterate over the elements multiple times. Custom iterators like ourResettableIteratorshould override this to returntrueif they support resetting.
内容的提问来源于stack exchange,提问作者Lando-L

