Scala-сравнение элемента trait val с абстрактным типом - PullRequest
3 голосов
/ 05 января 2011

Я пытаюсь выяснить, как выразить приведенный ниже код, используя абстрактные типы вместо использования параметров типа.

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

но это также не помогает, так как компилятор не считает, что сравнение определено. Кроме того, существует ли решение, в котором compare можно переместить в ключ черты, ограничив K (например, type K <: Ordered[K])?

Ответы [ 2 ]

4 голосов
/ 06 января 2011

Я думаю, вам нужен хотя бы один параметр типа, чтобы указать, что 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

Вот определение, которое будет применять ограничение во время компиляции, а также вытягивать определение сравнения в базовый член:

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 не являются подтипами Упорядоченного, но доступны неявные преобразования.

1 голос
/ 06 января 2011

Единственный способ исключить параметр типа из ключа, в то же время позволяя безопасно упорядочивать ключи, - это определить неявное преобразование из типа ключа в тип Упорядоченный ключ.Это также упрощает выделение метода сравнения.

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 (примечание. 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...