使用 Scala 2.8,您可以编写:
case class Vector3[T: Numeric](val x: T, val y: T, val z: T) {
override def toString = "(%s, %s, %s)" format (x, y, z)
def add(that: Vector3[T]) = new Vector3(
plus(x, that.x),
plus(y, that.y),
plus(z, that.z)
)
private def plus(x: T, y: T) = implicitly[Numeric[T]] plus (x, y)
}
让我解释一下。首先,T: Numeric 是一个上下文绑定,它隐式地为您的类提供了一个 Numeric[T] 实例。
Numeric[T] trait 提供对数值类型的操作,
trait Numeric[T] extends Ordering[T] {
def plus(x: T, y: T): T
def minus(x: T, y: T): T
def times(x: T, y: T): T
def negate(x: T): T
// other operations omitted
}
表达式 implicitly[Numeric[T]] 检索此隐式上下文,以便您可以对具体参数 x、y 和 z 执行诸如 plus 之类的操作,如上面的私有方法中所示。
您现在可以构造 add 和 Vector3 的不同实例,例如 Int 和 Double 的:
scala> Vector3(1,2,3) add Vector3(4,5,6)
res1: Vector3[Int] = (5, 7, 9)
scala> Vector3(1.1, 2.2, 3.3) add Vector3(4.4, 5.5, 6.6)
res2: Vector3[Double] = (5.5, 7.7, 9.899999999999999)
旁注:可以使用隐式转换将值转换为 Numeric[T].Ops 实例,这样可以改为编写以下代码:
def add(that: Vector3[T]) = new Vector3(x + that.x, y + that.y, z + that.z)
我故意选择不使用这些隐式转换,因为它们(可能)通过创建临时包装对象而导致一些性能损失。实际性能影响取决于 JVM(例如,它在多大程度上支持逃逸分析以避免堆上的实际对象分配)。使用上下文绑定和implicitly 避免了这种潜在的开销......以一些冗长为代价。