6

Mam trudny czas ze zrozumieniem, dlaczego kompilator Scala jest niezadowolony z tej definicji funkcji:Funkcja który ogólnie zajmuje typu i zwraca ten sam typ

def trimNonWordCharacters[T <: Iterable[String]](items: T): T = 
    items map { _.replaceAll("\\W", "") } 

Oto wynik 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", "") } 

Celem jest przekazanie dowolnej implementacji Iterable i uzyskanie tego samego typu wycofania. czy to możliwe?

+0

Duplikat http://stackoverflow.com/questions/8235462/returning-original-collection-type-in-generic -method –

+2

@LuigiPlinge To pytanie nie wymagało 'CanBuildFrom', ponieważ' filter' nie wymaga tego. To pytanie jest bardzo podobne, a __________ tego pytania z pewnością je pokrywa, ale tutaj potrzeba trochę więcej, aby to zadziałało. –

Odpowiedz

13

Sposób map na Iterable zwraca Iterable, więc nawet jeśli T jest podklasą Iterable, to map metoda zwróci Iterable.

Aby lepiej pisać, trzeba by napisać to tak:

import scala.collection.IterableLike 
def trimNonWordCharacters[T <: Iterable[String]](items: T with IterableLike[String, T]): T = 
    items map { _.replaceAll("\\W", "") } 

jednak, że nie będzie działać albo, ponieważ nie ma informacji, że niech się mapa na T wygenerować inny T. Na przykład odwzorowanie BitSet na String nie może skutkować uzyskaniem BitSet. Potrzebujemy więc czegoś innego: czegoś, co uczy, jak zbudować model T z T, gdzie odwzorowane elementy są typu String. Tak:

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", "") } 
+0

Dziękuję bardzo - twoje wyjaśnienie jest bardzo pouczające i teraz w końcu znam sposób na użycie 'CanBuildFrom' (!) –

0

[Wprowadzanie jako odpowiedź zamiast komentarza, ponieważ kod w komentarzach nie formatuje poprawnie]

@Daniel, dzięki za wyjaśnienie, ja też okazało się przydatne. Jak iterowalny wywodzi IterableLike dodaje również wydaje się działać, i jest nieco bardziej zwarty:

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", "") }