你基本上想要Polymorphism,也就是将同一个操作应用于多种类型的能力。
事实证明,在这种情况下,最好的方法之一是Typeclass,因为它可以灵活地接受外部类型。
如果您只想接受任何数字,那么您只需要使用作为标准库一部分的Numeric 类型类;正如已经显示的here & here。
但是,由于您还想对集合类型进行抽象,您可能需要使用 Seq 特征组合该集合类型以及子类型多态性。
或者,您还可以通过为集合提供类型类来将其提升到新的水平。
如果你愿意使用cats library,你可以只使用Monoid作为组合部分,Foldable作为迭代(折叠)部分。
import cats.{Foldable, Monoid}
import cats.syntax.all._
def usingCats[C[_] : Foldable, A : Monoid](data: C[A]): A =
data.combineAll
可以这样使用:
import scala.collection.immutable.ArraySeq
val ints = List(1, 2, 3)
val doubles = ArraySeq(0.0d, 5.0d, 10.0d)
val strings = LazyList("A", "B", "C")
usingCats(ints) // res: Int = 6
usingCats(doubles) // res: Double = 15.0
usingCats(strings) // res: String = ABC
但是,您也可以自己实现它:
(但您会重复库已经提供的大量代码)
trait MyFoldable[C[_]] {
def fold[A, B](ca: C[A])(z: B)(op: (B, A) => B): B
}
object MyFoldable {
implicit final val MyFoldableList: MyFoldable[List] =
new MyFoldable[List] {
override def fold[A, B](list: List[A])(z: B)(op: (B, A) => B): B =
list.foldLeft(z)(op)
}
implicit final val MyFoldableArraySeq: MyFoldable[ArraySeq] =
new MyFoldable[ArraySeq] {
override def fold[A, B](arr: ArraySeq[A])(z: B)(op: (B, A) => B): B =
arr.foldLeft(z)(op)
}
implicit final val MyFoldableLazyList: MyFoldable[LazyList] =
new MyFoldable[LazyList] {
override def fold[A, B](lazyList: LazyList[A])(z: B)(op: (B, A) => B): B =
lazyList.foldLeft(z)(op)
}
}
trait MyMonoid[A] {
def empty: A
def combine(a1: A, a2: A): A
}
object MyMonoid {
implicit final val MyMonoidInt: MyMonoid[Int] =
new MyMonoid[Int] {
override final val empty: Int = 0
override final def combine(i1: Int, i2: Int): Int =
i1 + i2
}
implicit final val MyMonoidDouble: MyMonoid[Double] =
new MyMonoid[Double] {
override final val empty: Double = 0.0d
override final def combine(d1: Double, d2: Double): Double =
d1 + d2
}
implicit final val MyMonoidString: MyMonoid[String] =
new MyMonoid[String] {
override final val empty: String = ""
override final def combine(s1: String, s2: String): String =
s1 + s2
}
}
def byHand[C[_], A](data: C[A])
(implicit foldable: MyFoldable[C], monoid: MyMonoid[A]): A =
foldable.fold(data)(monoid.empty)(monoid.combine)
这会产生相同的结果:
byHand(ints) // res: Int = 6
byHand(doubles) // res: Double = 15.0
byHand(strings) // res: String = ABC
可以看到运行here的代码。