在Scala中访问类型参数的类级别值

时间:2014-06-23 17:42:53

标签: scala

我有一个特征和一个实现它的案例类。实现覆盖的特征的一个特征是默认值。我找不到从通过该特征的特定实现参数化的类访问此默认值的好方法。

这是最小的代码,因此它不再真正展示出动机,但它确实证明了错误:

import scala.language.implicitConversions

trait Distance[T] {
  val Zero: T
  def +( that: T ): T
}

case class DoubleDistance( val v: Double ) extends Distance[DoubleDistance] {
  val Zero = DoubleDistance( 0.0 )
  def +( that: DoubleDistance ) = DoubleDistance( v + that.v )
}

object DistanceImplicits {
  implicit def DoubleToDistance( v: Double ) = new DoubleDistance( v )
}

class User[T<:Distance[T]] {
  val default: T = T.Zero // This line gives me a compilation error
}

我得到的错误是

not found: value T

当我需要在Array[T]课程中构建User时,我可以通过在我的参数中添加implicit typetag:ClassTag[T]来实现这一点,但这似乎没有任何效果

3 个答案:

答案 0 :(得分:2)

首先,为什么这不起作用:考虑Distance的不同实现。

case class DoubleDistance1(val v: Double) extends Distance[DoubleDistance1] {
  val Zero = this
  def +(that: DoubleDistance1) = ??? // doesn't matter
}

您期望DoubleDistance1.Zero的意思是什么?您可以使用“类型类”来使其工作:

trait DistanceOps[T] {
  val zero: T
  def add(d1: T, d2: T): T
}

// just to let you write distance1 + distance2
implicit class RichDistance[T](d: T)(implicit ops: DistanceOps[T]) {
  def +(other: T) = ops.add(d, other)
}

case class DoubleDistance(v: Double)

object DoubleDistance {
  implicit object DoubleDistanceOps extends DistanceOps[DoubleDistance] {
    val zero = DoubleDistance(0.0)
    def add(d1: DoubleDistance, d2: DoubleDistance) = DoubleDistance(d1.v + d2.v)
  }
}

// how to use
class User[T](implicit ops: DistanceOps[T]) {
  val default: T = ops.zero
}

答案 1 :(得分:2)

这看起来像是type class pattern的经典用例。不是将Distance特征的实例与感兴趣的每个相关联,而是将其与感兴趣的每个类型相关联:

trait Distance[T] {
  val Zero: T
  def +( a: T, b: T ): T
}

implicit object DoubleDistance extends Distance[Double] {
  val Zero = 0.0
  def +( a: Double, b: Double ) = a + b
}

class User[T : Distance] {
  val default: T = implicitly[Distance[T]].Zero 
}

答案 2 :(得分:0)

Zero应该来自哪里?你想做这样的事吗?

class User[T<:Distance[T]] {
  self:Distance[T] =>
  val default: T = Zero
}