Arn*_*rne 24 polymorphism scala type-parameter
我正在尝试创建一个对所有数字类型通用的Vector类.我最初的尝试是为所有类型编写一个类,如下所示:
class Vector3f(val x:Float, val y:Float, val z:Float)
Run Code Online (Sandbox Code Playgroud)
因为scala支持专门的注释,所以我可以使用它来为所有数字类型生成这些类
class Vector3[A <: What?](val x:A,val y:A, val z:A)
Run Code Online (Sandbox Code Playgroud)
但我发现作为数字的超级类型的所有东西都是AnyVal,但AnyVal不支持+ - */.那么正确的方法是什么,但不牺牲未装箱数字类型的性能?
Dan*_*ral 16
你不能.不是现在.也许何时,如果,Numeric专业.
假设您可以获得最简单的参数化类:
class Vector3[@specialized T](val x: T, val y: T, val z: T)(implicit num: Numeric[T]) {
def +(other: Vector3[T]) = new Vector3(num.plus(x, other.x), num.plus(y, other.y), num.plus(z, other.z))
}
Run Code Online (Sandbox Code Playgroud)
该方法+将编译成大致类似的东西:
override <specialized> def +$mcD$sp(other: Vector3): Vector3 = new Vector3$mcD$sp(
scala.Double.unbox(
Vector3$mcD$sp.this.Vector3$$num.plus(
scala.Double.box(Vector3$mcD$sp.this.x()),
scala.Double.box(other.x$mcD$sp()))),
scala.Double.unbox(
Vector3$mcD$sp.this.Vector3$$num.plus(
scala.Double.box(Vector3$mcD$sp.this.y()),
scala.Double.box(other.y$mcD$sp()))),
scala.Double.unbox(
Vector3$mcD$sp.this.Vector3$$num.plus(
scala.Double.box(Vector3$mcD$sp.this.z()),
scala.Double.box(other.z$mcD$sp()))),
Vector3$mcD$sp.this.Vector3$$num);
Run Code Online (Sandbox Code Playgroud)
这是scalac -optimize -Xprint:jvm输出.现在每个专用类型都有子类,所以你可以初始化Vector3没有拳击,但只要Numeric不专业,你就不能再进一步了.
嗯......你可以编写自己的,Numeric并专注于那个,但是,在那一点上,我不确定你通过首先将类参数化来获得什么.
简短的回答是:你无法获得完整的表现.或者至少我没有找到任何可以提供完整性能的东西.(我曾尝试在一段时间正是这种使用情况下,我放弃了,并写了一个代码生成器来代替,特别是因为你不能处理不同向量长度一般要么.)
我很高兴能够以其他方式展示,但到目前为止,我所尝试的一切都在运行时增加了很小(30%)到最大(900%).
编辑:这是一个显示我的意思的测试.
object Specs {
def ptime[T](f: => T): T = {
val t0 = System.nanoTime
val ans = f
printf("Elapsed: %.3f s\n",(System.nanoTime-t0)*1e-9)
ans
}
def lots[T](n: Int, f: => T): T = if (n>1) { f; lots(n-1,f) } else f
sealed abstract class SpecNum[@specialized(Int,Double) T] {
def plus(a: T, b: T): T
}
implicit object SpecInt extends SpecNum[Int] {
def plus(a: Int, b: Int) = a + b
}
final class Vek[@specialized(Int,Double) T](val x: T, val y: T) {
def +(v: Vek[T])(implicit ev: SpecNum[T]) = new Vek[T](ev.plus(x,v.x), ev.plus(y,v.y))
}
final class Uek[@specialized(Int,Double) T](var x: T, var y: T) {
def +=(u: Uek[T])(implicit ev: SpecNum[T]) = { x = ev.plus(x,u.x); y = ev.plus(y,u.y); this }
}
final class Veq(val x: Int, val y: Int) {
def +(v: Veq) = new Veq(x + v.x, y + v.y)
}
final class Ueq(var x: Int, var y: Int) {
def +=(u: Ueq) = { x += u.x; y += u.y; this }
}
def main(args: Array[String]) {
for (i <- 1 to 6) {
ptime(lots(1000000,{val v = new Vek[Int](3,5); var u = new Vek[Int](0,0); var i=0; while (i<100) { u = (u+v); i += 1 }; u}))
ptime(lots(1000000,{val v = new Veq(3,5); var u = new Veq(0,0); var i=0; while (i<100) { u = (u+v); i += 1 }; u}))
ptime(lots(1000000,{val v = new Uek[Int](3,5); val u = new Uek[Int](0,0); var i=0; while (i<100) { u += v; i += 1 }; u}))
ptime(lots(1000000,{val v = new Ueq(3,5); val u = new Ueq(0,0); var i=0; while (i<100) { u += v; i += 1 }; u}))
}
}
}
Run Code Online (Sandbox Code Playgroud)
和输出:
Elapsed: 0.939 s
Elapsed: 0.535 s
Elapsed: 0.077 s
Elapsed: 0.075 s
Elapsed: 0.947 s
Elapsed: 0.352 s
Elapsed: 0.064 s
Elapsed: 0.063 s
Elapsed: 0.804 s
Elapsed: 0.360 s
Elapsed: 0.064 s
Elapsed: 0.062 s
Elapsed: 0.521 s <- Immutable specialized with custom numeric
Elapsed: 0.364 s <- Immutable primitive type
Elapsed: 0.065 s <- Mutable specialized with custom numeric
Elapsed: 0.065 s <- Mutable primitive type
...
Run Code Online (Sandbox Code Playgroud)
您可能希望使用此处描述的类型类模式:http://dcsobral.blogspot.com/2010/06/implicit-tricks-type-class-pattern.html
或者,您可以通过使用数字特征间接使用http://www.scala-lang.org/api/current/scala/math/Numeric.html