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

发布于 2024-10-10 15:20:43 字数 857 浏览 0 评论 0原文

我试图弄清楚如何使用抽象类型而不是使用类型参数来表达下面的代码。

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 比较 that.key

但这也会失败,因为编译器认为没有定义比较。另外,是否有一种解决方案可以通过限制 K 将 compare 移动到特征键中(例如 type K <: Ordered[K])?

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]. 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:

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 (e.g. type K <: Ordered[K])?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

城歌 2024-10-17 15:20:43

我认为您至少需要一个类型参数来指示 DoubleKeyStringKey 不具有可比性。写成 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

这是一个定义,它将在编译时强制执行约束,并将比较的定义拉入基本成员:

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

请注意,我使用了视图绑定,因为 DoubleString 不是 Ordered 的子类型,但有可用的隐式转换。

I think you need at least one type parameter to indicate that DoubleKey and say StringKey are not comparable. It would not make sense to write 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:

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.

美人如玉 2024-10-17 15:20:43

从 Key 中消除类型参数同时仍允许 Key 安全排序的唯一方法是定义从 Key 类型到 Ordered key 类型的隐式转换。这也使得分解比较方法变得简单。

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 会话(注意:将 Trait/object Key 包装在虚拟对象中以确保 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)

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. 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),

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文