我试图弄清楚如何使用抽象类型而不是使用类型参数来表达下面的代码。
trait Key[T] extends Ordered[Key[T]] {
val key:T
}
case class DoubleKey(key:Double) extends Key[Double] {
def compare(that:Key[Double]):Int = this.key compare that.key
}
我目前的版本如下:
trait Key extends Ordered[Key] {
type K
val key:K
}
case class DoubleKey(val key:Double) extends Key {
type K = Double
def compare(that:Key):Int = this.key compare that.key.asInstanceOf[K]
}
但是我对K型的显式转换不满意:that.key.asInstanceOf[K]
。是否有更好的/其他方法来使用抽象类型实现抽象成员的排序?
我还尝试确保that:Key
的类型为Double
:
def compare(that:Key { type K = Double } ):Int = this.key compare that.key
但这也失败了,因为编译器并不认为比较是定义的。此外,是否有解决办法可以通过限制K(例如compare
)将type K <: Ordered[K]
移入特征密钥?
答案 0 :(得分:4)
我认为您至少需要一个类型参数来表示DoubleKey
和StringKey
不具有可比性。写DoubleKey(1.0) < StringKey("foo")
使用您当前的设计,您可以获得一个类强制转换异常:
case class StringKey(val key:String) extends Key {
type K = String
def compare(that:Key):Int = this.key compare that.key.asInstanceOf[K]
}
StringKey("b") < DoubleKey(1.0) // ClassCastException
这是一个定义,它将在编译时强制执行约束,并将compare的定义拉入基本成员:
abstract class Key[K <% Ordered[K]] extends Ordered[Key[K]] {
val key:K
def compare(that:Key[K]): Int = key compare that.key
}
case class DoubleKey(key:Double) extends Key[Double]
case class StringKey(key:String) extends Key[String]
StringKey("b") < DoubleKey(1.0) // won't compile
请注意,我使用了视图绑定,因为Double
或String
不是Ordered的子类型,但有可用的隐式转换。
答案 1 :(得分:1)
从Key中消除类型参数同时仍然允许安全排序键的唯一方法是从Key类型定义隐式转换Ordered键类型。这也使得直接分析比较方法。
trait Key { type K ; val key : K }
object Key {
type PKey[KK] = Key { type K = KK }
implicit def keyIsOrdered[K <% Ordered[K]](lhs : PKey[K]) = new Ordered[PKey[K]] {
def compare(rhs : PKey[K]) = lhs.key compare rhs.key
}
}
case class DoubleKey(val key : Double) extends Key { type K = Double }
case class StringKey(val key : String) extends Key { type K = String }
示例REPL会话(nb.wrap trait / object键入虚拟对象以确保REPL将它们视为伴侣),
scala> DoubleKey(23) < DoubleKey(34)
res3: Boolean = true
scala> StringKey("foo") < StringKey("bar")
res4: Boolean = false
scala> StringKey("foo") < DoubleKey(23)
<console>:14: error: could not find implicit value for parameter ord: scala.math.Ordering[ScalaObject]
StringKey("foo") < DoubleKey(23)