6
如果你和我一樣,你偶爾想寫Scala集合或序列的增強方法,但是你想要綁定集合類型以及元素類型,而不僅僅是向Seq [T]上傳。您如何編寫綁定集合類型以及元素類型的通用Scala增強方法?
如果你和我一樣,你偶爾想寫Scala集合或序列的增強方法,但是你想要綁定集合類型以及元素類型,而不僅僅是向Seq [T]上傳。您如何編寫綁定集合類型以及元素類型的通用Scala增強方法?
有一種方法來做到這一點,並且它是這樣工作的:
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)
}
}
使用上述類型簽名模式,增強的方法都知道這兩個元素類型的T
(例如Int
或String
)和更高主觀序列類型S
(例如List
或Vector
),因此它可以精確地返回它被調用的序列類型。
許多序列方法可能需要CanBuildFrom
含義,將它們作爲隱含參數添加到Enhance
方法中,在上述示例中需要它們。
以下是一個樣品運行,顯示出期望的-kinded更高集合返回類型:
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)
您也可以定義類作爲'隱類增強[T,S [E] <:IterableLike [E,S [se]:(seq:S [T]){'然後你將不需要'asInstanceOf' –
如果你使用'map'或其他方法在新方法中使用'CanBuildFrom'實現。結果會以「Seq」出現。您需要將相關的隱式'CanBuildFrom'傳遞給'Enhance'類或該方法。 – Kolmar
謝謝@НиколайМитропольский和Kolmar,這兩個修改都非常有用!我重新編寫了我的原始答案,以表明他們的行動。 – eje