Hi have the following as bellow. It is supposed to be a function that calculate the average of a sequence.
def fun1[T <: { def toDouble:Double }] (seq:Seq[T]) = {
val q2 = seq map { _.toDouble }
val n = q2.size.toDouble
q2.sum / n
}
However I cannot pass Seq(1,2,3)
to fun1
. Why?
Structural types are very expensive on the JVM and you should avoid them. It stands to reason that only a Numeric
could be encoded as a Double
. Scala offers a Numeric
typeclass as a way to define generic operations on the so called "number types", so you don't actually need to use what you are proposing, the standard lib has you covered.
def fun1[T](seq: Seq[T])(ev: Numeric[T]): Double = {
val q2 = seq map ev.toDouble
val n = q2.size.toDouble
q2.sum / n
}
You don't really need to get more creative than that if all you want is your operation to be generic on numbers. Otherwise, you will have to implement your own typeclass.
trait Converter[T] {
def toDouble(source: T): Double
}
object Converter {
implicit def numericConvert[T : Numeric]: Converter[T] = new Converter[T] { def toDouble(source: T): Double = implicitly[Numeric[T]].toDouble(source)}
implicit object StringConverter extends Converter[String] = ...
}
Now to use the simple approach based on Numeric
, you could define a simple helper.
object Helper {
implicit class ColOps[
M[X] <: TraversableOnce[X],
T
](val col: M[T])(implicit ev: Numeric[T]) {
def average: Double = {
val q2 = col map ev.toDouble
val n = q2.size.toDouble
q2.sum / n
}
}
}
Now all you need to do is:
import Helper._
List(1, 2, 3).average
Seq(1, 2, 3).average
Set(5F, 2F, 3F).average
This is a bit more cool, since we can abstract over common collection types too.
def fun1[T <: AnyVal{ def toDouble:Double }] (seq:Seq[T]) = {
val q2 = seq map { _.toDouble }
val n = q2.size.toDouble
q2.sum / n
}
fun1(Seq(1, 2, 3))
It seems like the compiler infers the type as AnyRef. Defining it as AnyVal works. AnyRef is the supertype of all objects, while AnyVal is the supertype of all primitives.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.