Ответ 1
нерекурсивна
Я думаю, что ваш лучший вариант - сделать что-то вроде этого
object Rooms {
case class Room(title: String) {
def exits = exitMap(this)
}
val first:Room = Room("first")
val second:Room = Room("second")
private val exitMap = Map(first -> Map("S" -> second), second -> Map("N" -> first))
}
scala> Rooms.first.title
res: String = first
scala> Rooms.first.exits
res: scala.collection.immutable.Map[java.lang.String,Rooms.Room] = Map(S -> Room(second))
Это совершенно непреложно, и вы избегаете неприятных рекурсий.
Рекурсивный
Построение рекурсивной структуры требует гораздо большей осторожности, поскольку по умолчанию Scala не является ленивым. В частности, невозможно создать ленивый или вызываемый по имени параметр case class
. Поэтому для этого нужно использовать специализированную структуру данных.
Одним из вариантов может быть использование Stream
s:
case class LazyRoom(title: String, exits: Stream[LazyRoom])
object LazyRooms {
lazy val nullRoom: LazyRoom = LazyRoom("nullRoom", Stream.empty)
lazy val first: LazyRoom = LazyRoom("first", nullRoom #:: second #:: Stream.empty)
lazy val second: LazyRoom = LazyRoom("second", nullRoom #:: first #:: Stream.empty)
}
scala> LazyRooms.first.exits(1).title
res> String: second
Чтобы быть на стороне сохранения, я префикс фиктивной комнаты перед каждым Stream
, чтобы избежать преждевременного доступа. (Поток только ленив в хвосте, но не в его голове.) Специальная структура данных может избежать этого.
Очищенная версия
Мы можем сделать лучше с помощью вспомогательной функции call-by-name для выполнения грязной работы:
case class LazyRoom(title: String, exitMap: Stream[Map[String, LazyRoom]]) {
def exits = exitMap(1) // skip the Streams empty head
}
def _exitMap(mappedItems: => Map[String, LazyRoom]) = {
Map[String, LazyRoom]() #::
mappedItems #::
Stream.empty
}
object LazyRooms {
lazy val first: LazyRoom = LazyRoom("first", _exitMap(Map("South" -> second)))
lazy val second: LazyRoom = LazyRoom("second", _exitMap(Map("North" -> first)))
}
scala> LazyRooms.first.exits
res: Map[String,LazyRoom] = Map(South -> LazyRoom(second,Stream(Map(), ?)))