Я слышал, что в Scala есть типы, зависящие от пути. Это как-то связано с внутренними классами, но что это на самом деле означает и почему меня это волнует?
Я слышал, что в Scala есть типы, зависящие от пути. Это как-то связано с внутренними классами, но что это на самом деле означает и почему меня это волнует?
Ответы:
Мой любимый пример:
case class Board(length: Int, height: Int) {
case class Coordinate(x: Int, y: Int) {
require(0 <= x && x < length && 0 <= y && y < height)
}
val occupied = scala.collection.mutable.Set[Coordinate]()
}
val b1 = Board(20, 20)
val b2 = Board(30, 30)
val c1 = b1.Coordinate(15, 15)
val c2 = b2.Coordinate(25, 25)
b1.occupied += c1
b2.occupied += c2
// Next line doesn't compile
b1.occupied += c2
Итак, тип Coordinate
зависит от экземпляра, Board
из которого он был создан. С его помощью можно сделать все, что угодно, обеспечивая своего рода безопасность типов, которая зависит от значений, а не только от типов.
Это может показаться зависимым типом, но оно более ограничено. Например, тип occupied
зависит от значения Board
. Выше последняя строка не работает, потому что тип c2
- b2.Coordinate
, а occupied
тип - Set[b1.Coordinate]
. Обратите внимание, что можно использовать другой идентификатор с тем же типом b1
, поэтому это не идентификатор b1
, связанный с типом. Например, работает следующее:
val b3: b1.type = b1
val c3 = b3.Coordinate(10, 10)
b1.occupied += c3