risposta

7

C'è un modo per farlo, e funziona così:

object enhance { 
    import scala.language.higherKinds 
    import scala.language.implicitConversions 
    import scala.collection.SeqLike 
    import scala.collection.generic.CanBuildFrom 

    implicit class Enhance[T, S[E] <: SeqLike[E, S[E]]](seq: S[T]) { 
    def first3(implicit cbf: CanBuildFrom[S[T], T, S[T]]) = seq.take(3) 
    def foo = seq.iterator 
    def goo(implicit cbf: CanBuildFrom[Nothing, T, S[T]]) = foo.take(3).to[S] 
    def moo[U](f: T => U)(implicit cbf: CanBuildFrom[S[T], U, S[U]]) = seq.map(f) 
    } 
} 

Utilizzando il modello di firma tipo sopra, i metodi avanzati sono consapevoli sia del tipo di elemento T (es Int o String) e il tipo di sequenza più alto tipo S (ad esempio List o Vector) e quindi può restituire esattamente il tipo di sequenza su cui è stato chiamato.

Molti metodi di sequenza possono richiedere impliciti CanBuildFrom, che vengono aggiunti ai metodi Enhance come parametri impliciti, dove sono necessari negli esempi sopra.

A seguito di un esempio di esecuzione, che mostra i tipi di raccolta di ritorno superiore kinded desiderati:

scala> import enhance._ 
import enhance._ 

scala> (1 to 10).toList.first3 
res0: List[Int] = List(1, 2, 3) 

scala> (1 to 10).toVector.first3 
res1: Vector[Int] = Vector(1, 2, 3) 

scala> (1 to 10).toList.goo 
res2: List[Int] = List(1, 2, 3) 

scala> (1 to 10).toVector.goo 
res3: Vector[Int] = Vector(1, 2, 3) 

scala> (1 to 10).toList.moo(_.toDouble) 
res4: List[Double] = List(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) 

scala> (1 to 10).toVector.moo(_.toDouble) 
res5: Vector[Double] = Vector(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) 
+4

Inoltre è possibile definire classe come classe 'implicita Migliora [T, S [E] <: IterableLike [E, S [E]]] (seq: S [T]) {'e quindi non avrai bisogno di' asInstanceOf ' –

+3

Non funzionerà, se usi' map' o qualsiasi altro metodo che prende un 'CanBuildFrom' nel nuovo metodo implementazioni. Il risultato sarebbe appena uscito come 'Seq'. Dovresti passare un "CanBuildFrom" implicito rilevante alla classe 'Enhance' o al metodo. – Kolmar

+1

Grazie a @ НиколайМитропольский e Kolmar, entrambe queste modifiche sono molto utili! Ho rielaborato la mia risposta originale per mostrarli in azione. – eje

Problemi correlati