【问题标题】:Type parameterization in ScalaScala 中的类型参数化
【发布时间】:2011-02-19 16:12:10
【问题描述】:

所以我现在正在学习 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 = "&lt"+x+", "+y+", "+z+"&gt"
  def add(that: Vector3[T]) = new Vector3(x+that.x, y+that.y, z+that.z)
}

问题是我不断收到此错误:

错误:类型不匹配;
发现: T
必需:字符串
def 添加(即:Vector3[T])= 新 Vector3(x+that.x, y+that.y, z+that.z)

我试过注释掉上面的“toString”方法,但这似乎没有任何效果。谁能告诉我我做错了什么?

【问题讨论】:

    标签: templates scala


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      您没有限制类型参数 T,因此编译器回退到将 + 解释为字符串连接。

      【讨论】:

        【解决方案3】:

        问题是T。它的类型为Any,但Any 没有+ 运算符。关于 String 的错误有点错过领先。所以你将不得不定义绑定到一个类型的最小值。

        【讨论】:

        • 在 2.8 中这是Ops,或者我被告知。我不知道在 2.7 中要做什么,但我是 Scala 新手。
        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-05
          • 1970-01-01
          • 1970-01-01
          • 2018-09-24
          • 1970-01-01
          • 1970-01-01
          • 2021-04-20
          相关资源
          最近更新 更多