Scala 2.8 CanBuildFrom
Следуя еще одному вопросу, который я задал, прорыв Scala 2.8 , я хотел узнать немного больше о методе Scala TraversableLike[A].map
чья подпись такова:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Обратите внимание на несколько вещей об этом методе:
- Требуется функция, поворачивающая каждый
A
в проходящей вB
- Он возвращает
That
и принимает неявный аргумент типаCanBuildFrom[Repr, B, That]
.
Я могу назвать это следующим образом:
- Что такое «контекст» в Scala?
- Когда в Scala требуется @uncheckedVariance и почему она используется в GenericTraversableTemplate?
- Как записать файл в Scala?
- Реализация доходности (доходность доходности) с использованием продолжений Scala
- Какая IDE для Scala 2.8?
> val s: Set[Int] = List("Paris", "London").map(_.length) s: Set[Int] Set(5,6)
То, что я не могу понять, заключается в том, что компилятор реализует тот факт, что That
привязано к B
(то есть, это некоторая коллекция B). Параметры типа выглядят не зависимыми как от подписи выше, так и от сигнатуры признака CanBuildFrom
:
trait CanBuildFrom[-From, -Elem, +To]
Как компилятор Scala гарантирует, что That
невозможно заставить во что-то, что не имеет смысла?
> val s: Set[String] = List("Paris", "London").map(_.length) //will not compile
Как компилятор решает, какие неявные объекты CanBuildFrom
находятся в области вызова?
- Scala 2.8 breakOut
- Согласование шаблонов Scala с именем переменной нижнего регистра
- Является ли библиотека коллекций Scala 2.8 «самой длинной записью о самоубийстве в истории»?
- Что такое продолжения Скалы и зачем их использовать?
- Конструктор перегрузки для classов Case Scala?
- Что означают <: <, <% <, и =: = mean в Scala 2.8, и где они задокументированы?
Обратите внимание, что второй аргумент для map
является неявным аргументом. Должна быть неявная область действия с соответствующими типами, или, в противном случае, вы должны передать такой аргумент.
В вашем примере That
должен быть Set[String]
, B должен быть Int
и Repr
должен быть List[String]
. Поэтому для компиляции вам нужен следующий неявный объект в области видимости:
implicit object X: CanBuildFrom[List[String], Int, Set[String]]
В сфере нет такой вещи. Кроме того, breakOut
не может предоставить его, потому что сам он нуждается в неявном CanBuildFrom
, первым типом которого может быть любой class (контравариантный потомок Nothing
), но в противном случае он ограничен другими типами.
Посмотрите, например, на фабрику CanBuildFrom
из сопутствующего объекта List
:
implicit def canBuildFrom [A] : CanBuildFrom[List, A, List[A]]
Поскольку он связывает второй и третий параметры через A
, подразумеваемый вопрос не будет работать.
Итак, как узнать, где искать, в отношении таких имплицитов? Прежде всего, Scala импортирует несколько вещей во все области. Сейчас я могу вспомнить следующий импорт:
import scala.package._ // Package object import scala.Predef._ // Object // import scala.LowPriorityImplicits, class inherited by Predef import scala.runtime._ // Package
Поскольку мы обеспокоены имплицитами, обратите внимание, что при импорте вещей из пакетов единственными возможными могут быть синглтоны. С другой стороны, когда вы импортируете объекты из объектов (одноточечных), вы можете иметь неявные определения, значения и одиночные числа.
Прямо сейчас есть CanBuildFrom
implicits внутри Predef
и LowPriorityImplicits
, которые связаны со строками. Они позволяют нам написать "this is a string" map (_.toInt)
.
Таким образом, запрет этих автоматических импорта и явный импорт вы делаете, где еще можно найти неявное? Одно место: объекты-компаньоны экземпляра, на который применяется метод.
Я говорю сопутствующий объект s во множественном числе, потому что сопутствующие объекты всех признаков и classов, унаследованные classом рассматриваемого экземпляра, могут содержать соответствующие импликации. Я не уверен, что сам экземпляр может содержать неявный. Честно говоря, я не могу воспроизвести это прямо сейчас, поэтому я, конечно, ошибаюсь.
Во всяком случае, загляните внутрь объектов-компаньонов.
object ArrayBuffer extends SeqFactory[ArrayBuffer] { /** $genericCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArrayBuffer[A]] = new GenericCanBuildFrom[A] def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A] }