Функция, которая в общем случае принимает тип и возвращает тот же тип
Мне сложно понять, почему компилятор 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 и получить тот же тип возврата. Возможно ли это?
Ответы
Ответ 1
Метод 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
. Например, отображение a 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", "") }
Ответ 2
[Ввод как ответ, а не комментарий, потому что код в комментариях не форматируется должным образом]
@Даниэль, спасибо за объяснение, я также счел это полезным. Поскольку 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", "") }