[英]Generic Type `toDouble` in Scala
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
. 但是我不能将
Seq(1,2,3)
传递给fun1
。 Why? 为什么?
Structural types are very expensive on the JVM and you should avoid them. 结构类型在JVM上非常昂贵,您应该避免使用它们。 It stands to reason that only a
Numeric
could be encoded as a Double
. 有理由认为,只有
Numeric
可以被编码为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. Scala提供了一个
Numeric
类型类作为在所谓的“数字类型”上定义泛型操作的方式,因此您实际上不需要使用您提出的内容,因为标准库已经涵盖了。
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. 现在,要使用基于
Numeric
的简单方法,您可以定义一个简单的帮助器。
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. 似乎编译器将类型推断为AnyRef。 Defining it as AnyVal works.
将其定义为AnyVal即可。 AnyRef is the supertype of all objects, while AnyVal is the supertype of all primitives.
AnyRef是所有对象的超类型,而AnyVal是所有基元的超类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.