在Scala中键入参数化

时间:2010-05-14 18:48:47

标签: templates scala

所以我现在正在学习Scala,我正在尝试创建一个矢量空间为3(x,y,z坐标)的抽象矢量类。我正在尝试将这些向量中的两个与以下代码一起添加:


package math

class Vector3[T](ax:T,ay:T,az:T) {
  def x = ax
  def y = ay
  def z = az
  override def toString = "<"+x+", "+y+", "+z+">"
  def add(that: Vector3[T]) = new Vector3(x+that.x, y+that.y, z+that.z)
}

问题是我一直收到这个错误:

  

错误:类型不匹配;
发现:   T

要求:字符串
def   add(that:Vector3 [T])= new   Vector3(x + that.x,y + that.y,   Z + that.z)

我已经尝试过评论上面的“toString”方法,但这似乎没有任何影响。谁能告诉我我做错了什么?

4 个答案:

答案 0 :(得分:8)

您没有约束类型参数T,因此编译器会回退到+作为字符串连接的解释。

答案 1 :(得分:8)

使用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 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等操作,如上面的私有方法所示。

您现在可以构建addVector3的不同实例,例如IntDouble

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可以避免这种潜在的开销......代价是一些冗长。

答案 2 :(得分:6)

问题是T。它的类型为Any,但Any没有+运算符。关于String的错误有点失误。因此,您必须将min绑定到一个类型。

答案 3 :(得分:4)

当然,@ sblundy和@Randall Schulz的答案都是正确的,但是如果你需要一些关于如何约束T的更具体的建议那么:

class Vector3[T <% Double](ax:T,ay:T,az:T) {
...
}