简体   繁体   English

特征val成员与抽象类型的Scala比较

[英]Scala compare of trait val member with abstract type

im trying to figure out how to express the below code using abstract types instead of using type parameters. 我试图弄清楚如何使用抽象类型而不是使用类型参数来表达下面的代码。

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
}

My current version looks as follows: 我当前的版本如下:

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]
}

But I'm not happy with the explicit casting to the type K: that.key.asInstanceOf[K] . 但是我对K类型的显式转换不满意: that.key.asInstanceOf[K] Are there better/other ways to achieve the ordering on an abstract member using abstract types? 是否有更好的/其他方法来使用抽象类型实现抽象成员的排序?

I have also tried to ensure that the type of that:Key is a Double : 我也试图确保它的类型that:KeyDouble

def compare(that:Key { type K = Double } ):Int = this.key compare that.key

but this also fails since the compiler doesnt think compare is defined. 但这也失败了,因为编译器并不认为比较是定义的。 Also, is there a solution where compare can be moved into the trait Key by restricting K (eg type K <: Ordered[K] )? 此外,是否有一种解决方案,可以通过限制K(例如, type K <: Ordered[K]compare移入特征密钥?

I think you need at least one type parameter to indicate that DoubleKey and say StringKey are not comparable. 我认为你需要至少一个类型参数来表明DoubleKeyStringKey不具有可比性。 It would not make sense to write DoubleKey(1.0) < StringKey("foo") DoubleKey(1.0) < StringKey("foo")是没有意义的

With your current design you could get a class cast exception: 使用您当前的设计,您可以获得类强制转换异常:

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

Here is a definition that will enforce the constraint at compile time and also pull the definition of compare into the base member: 这是一个定义,它将在编译时强制执行约束,并将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

Note that I used a view bound, as Double or String aren't subtypes of Ordered but there are implicit conversions available. 请注意,我使用了视图绑定,因为DoubleString不是Ordered的子类型,但有可用的隐式转换。

The only way to eliminate the type parameter from Key whilst still allowing Keys to be safely ordered is to define an implicit conversion from the Key type the the Ordered key type. 从Key中消除类型参数同时仍然允许安全地排序键的唯一方法是从Key类型定义隐式转换Ordered键类型。 This also makes it straightforward to factor out the compare method. 这也使得分析比较方法变得简单。

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 }

Sample REPL session (nb. wrap trait/object Key in a dummy object to ensure the REPL sees them as companions), 示例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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM