Функция, которая в общем случае принимает тип и возвращает тот же тип
Мне трудно понять, почему компилятор Scala недоволен этим определением функции:
def trimNonWordCharacters[T <: Iterable[String]](items: T): T =
items map { _.replaceAll("\\W", "") }
Вот результат REPL:
scala> def trimNonWordCharacters[T <: Iterable[String]](items: T): T =
items map { _.replaceAll("\\W", "") }
<console>:5: error: type mismatch;
found : Iterable[java.lang.String]
required: T
def trimNonWordCharacters[T <: Iterable[String]](items: T): T = items map { _.replaceAll("\\W", "") }
Цель состоит в том, чтобы передать любую реализацию Iterable и получить тот же тип возврата. Это возможно?
2 ответа
map
метод на Iterable
возвращает Iterable
так что даже если T
это подкласс Iterable
, его map
метод вернется Iterable
,
Чтобы лучше печатать, вы должны написать это так:
import scala.collection.IterableLike
def trimNonWordCharacters[T <: Iterable[String]](items: T with IterableLike[String, T]): T =
items map { _.replaceAll("\\W", "") }
Однако это тоже не сработает, потому что нет информации, позволяющей карте T
создать другой T
, Например, отображение BitSet
в String
не может привести к BitSet
, Поэтому нам нужно что-то еще: что-то, что учит, как построить T
из T
где сопоставленные элементы имеют тип String
, Как это:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
def trimNonWordCharacters[T <: Iterable[String]]
(items: T with IterableLike[String, T])
(implicit cbf: CanBuildFrom[T, String, T]): T =
items map { _.replaceAll("\\W", "") }
[Ввод в качестве ответа, а не комментария, потому что код в комментариях не форматируется должным образом]
@Daniel, спасибо за объяснение, я также нашел это полезным. Поскольку Iterable является производным от IterableLike, похоже, что работает следующее и немного более компактно:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
def trimNonWordCharacters[T <: IterableLike[String, T]]
(items: T)
(implicit cbf: CanBuildFrom[T, String, T]): T =
items map { _.replaceAll("\\W", "") }