Страницы

Поиск по вопросам

вторник, 12 февраля 2019 г.

Логика и назначение Product trait

Столкнулся с проблемой непонимания как работает trait Product. Пример:
List(1,2).productIterator.toList
Возвращает
List[Any] = List(1, List(2))
Покопавшись в документации пока не смог найти ответа на вопрос почему 2-ой элемент возвращается как List(2) а не просто 2. Спасибо.


Ответ

Для начала объясню что такое List, потом объясню как работает productIterator
И так List - это абстрактный класс, а значит создать его экземпляр нельзя. То что выглядит как List - на самом деле один из его наследников. У класса List два наследника - кейс-класс :: и кейс-объект Nil
Давай посмотрим на их реализацию:
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] { override def tail : List[B] = tl override def isEmpty: Boolean = false }
case object Nil extends List[Nothing] { override def isEmpty = true override def head: Nothing = throw new NoSuchElementException("head of empty list") override def tail: List[Nothing] = throw new UnsupportedOperationException("tail of empty list") // Removal of equals method here might lead to an infinite recursion similar to IntMap.equals. override def equals(that: Any) = that match { case that1: scala.collection.GenSeq[_] => that1.isEmpty case _ => false } }
То, что Nil - это пустой список, знают многие, поэтому рассмотрим кейс-класс ::. Как видишь у него два поля - head и tl. Заметь что head- это один элемент, а tl - коллекция(List). Т.е. когда мы пишем
List(1)
на самом деле создается такой кейс-класс:
::(1, Nil) ::(head = 1, tl = Nil)//тоже самое с именованными параметрами
А когда ты создаешь List(1, 2) на самом деле создается такое:
::(1, ::(2, Nil))
::(head = 1, tl = ::(2, Nil)) //тоже самое с именованными параметрами
Обрати внимание на то, что второй параметр имеет тип List, а значит какого бы ты наследника не передал (:: или Nil) - виден он будет как List
Теперь про productIterator, этот метод возвращает итератор на аргументы класса. В нашем случае у объекта Nil - нету аргументов, а у класса :: есть всего два аргумента - head и tl. Их значения ты и видишь.
P.S. А метод productIterator у них есть - благодаря тому, что они кейс-класс и кейс-объект.
Полезные материалы:
http://www.alessandrolacava.com/blog/scala-case-classes-in-depth/ http://www.scala-lang.org/api/current/scala/collection/immutable/List.html исходники Scala

Комментариев нет:

Отправить комментарий