6

Sto avendo un momento difficile comprendere perché il compilatore Scala è scontento di questa definizione di funzione:funzione che prende genericamente un tipo e restituisce lo stesso tipo

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

Ecco la REPL uscita:

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

L'obiettivo è di passare a qualsiasi implementazione di un Iterable e ottenere lo stesso tipo di back-out. È possibile?

+0

duplicati di http://stackoverflow.com/questions/8235462/returning-original-collection-type-in-generic -metodo –

+2

@LuigiPlinge Quella domanda non ha bisogno di 'CanBuildFrom', poiché' filter' non lo richiede. Questa domanda è molto simile, e il _title_ di quella domanda lo copre certamente, ma qui serve un po 'di più per farlo funzionare. –

risposta

13

Il metodo map su Iterable restituisce un Iterable, quindi, anche se T è una sottoclasse di Iterable, è map metodo restituirà Iterable.

per ottenere una migliore digitazione, dovreste scrivere in questo modo:

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

Tuttavia, questo sistema non funziona neanche, perché non c'è alcuna informazione che ha lasciato una mappa su T per generare un'altra T. Ad esempio, la mappatura di BitSet in un String non può comportare un valore BitSet. Quindi abbiamo bisogno di qualcos'altro: qualcosa che insegna come costruire uno T, dove gli elementi mappati sono di tipo String. Come questo:

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

Grazie mille- La tua spiegazione è molto istruttiva e ora so finalmente come usare 'CanBuildFrom' (!) –

0

[Entrare come una risposta piuttosto che un commento perché il codice nei commenti non formattare correttamente]

@ Daniel, grazie per la spiegazione, ho trovato anche utile. Come Iterable deriva dal IterableLike, il seguente sembra anche per lavorare, ed è leggermente più compatto:

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