6

Estoy teniendo un tiempo difícil entender por qué el compilador Scala no está contenta con esta función definición:de funciones, que genéricamente toma un tipo y devuelve el mismo tipo

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

Aquí es el REPL de salida:

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

El objetivo es pasar cualquier implementación de un Iterable y obtener el mismo tipo de retroceso. es posible?

+0

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

+2

@LuigiPlinge Esa pregunta no necesitaba 'CanBuildFrom', ya que' filter' no lo requiere. Esta pregunta es muy similar, y el título de esa pregunta ciertamente la cubre, pero aquí se requiere un poco más para que funcione. –

Respuesta

13

El método map en Iterable devuelve un Iterable, por lo que incluso si T es una subclase de Iterable, es map método devolverá Iterable.

para obtener mejores mecanografía, que tendría que escribir así:

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

Sin embargo, eso no va a funcionar bien, porque no hay ninguna información que permita que un mapa en T para generar otra T. Por ejemplo, asignar un BitSet en un String no puede dar como resultado un BitSet. Entonces, necesitamos algo más: algo que enseñe cómo construir un T desde un T, donde los elementos mapeados son del tipo String. De esta manera:

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

Muchas gracias- Su explicación es muy informativa y ahora sé por fin cómo usar 'CanBuildFrom' (!) –

0

[Entrar como una respuesta en lugar de un comentario, porque el código en los comentarios no formatea correctamente]

@ Daniel, gracias por la explicación, también encontraron útil. Como Iterable deriva de IterableLike, lo siguiente también parece funcionar, y es ligeramente más compacto:

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