Jeśli jesteś podobny do mnie, czasami chcesz pisać ulepszone metody do kolekcji lub sekwencji Scala, ale chcesz powiązać typ kolekcji, a także typ elementu, a nie tylko upcast na Seq [T].Jak można pisać ogólne metody poprawy Scala, które wiążą typ kolekcji, a także typ elementu?
6
A
Odpowiedz
7
Jest sposób, aby to zrobić, i to działa tak:
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)
}
}
Stosując wzór rodzaj podpisu powyżej, ulepszone metody są świadomi zarówno typu elementu T
(np Int
lub String
) i typem o wyższej ładowności typu S
(np. List
lub Vector
), dzięki czemu może on zwrócić dokładnie ten typ sekwencji, na który został wywołany.
Wiele metod sekwencji może wymagać CanBuildFrom
implicits, które są dodawane do metod jako niejawne parametry, gdzie są potrzebne w powyższych przykładach.
Poniżej bieg próbkę, wykazując pożądane wyższe kinded rodzajów powrotne kolekcji:
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)
Również można określić klasę jako 'ukryte klasy Ulepsz [T, S [k] <: IterableLike [E, S [E]]] (seq: S [T]) {'i wtedy nie będziesz potrzebował' asInstanceOf ' –
To nie zadziała, jeśli użyjesz' map' lub jakiejkolwiek innej metody, która bierze 'CanBuildFrom' w nowej metodzie wdrożenia. Rezultat wypadłby po prostu jako "Seq". Musiałbyś przekazać odpowiedni niejawny 'CanBuildFrom' do klasy' Enhance' lub do metody. – Kolmar
Dzięki @ НиколайМитропольский i Kolmar, obie te modyfikacje są bardzo przydatne! Przebudowałem swoją oryginalną odpowiedź, aby pokazać je w akcji. – eje