Функция, которая в общем случае принимает тип и возвращает тот же тип

Мне трудно понять, почему компилятор 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", "") }
Другие вопросы по тегам