无法在scala枚举中使用路径相关类型

时间:2015-03-26 12:55:04

标签: scala playframework

我尝试在Scala的枚举中围绕路径依赖类型旋转,同时为Play2进行读取/写入。这是我到目前为止的代码,它有效,但有一个asInstanceOf:

implicit def enumerationReads[T <: Enumeration](implicit t: T): Reads[t.Value] = {
    val validationError = ValidationError("error.expected.enum.name", t.values.mkString(", "))
    Reads.of[String].filter(validationError)(s ⇒ t.values.exists(v ⇒ v.toString == s)).map(t.withName(_))
  }

implicit def enumerationValueSetReads[T <: Enumeration](implicit t: T): Reads[t.ValueSet] =
    Reads.seq(enumerationReads[T]).map(seq ⇒ t.ValueSet(seq.asInstanceOf[Seq[t.Value]]: _*))

如何摆脱最后一行的asInstanceOf?我尝试将enumerationReads键入为enumerationReads [t.Value],但这并不起作用,编译器在t.ValueSet的参数中抱怨Seq [t.Value]无法转换为Seq [t.Value]。是的,这对我来说也没有意义,直到我开始意识到这些不同的可能实际上是不同的,因为它们被用在封闭中。

那么,怎样做才能让我的代码超级自由地asInstanceOf免费?

1 个答案:

答案 0 :(得分:2)

以下代码可能会起到作用:

implicit def enumerationReads(t : Enumeration) : Reads[t.Value] = {
    val validationError = ValidationError("error.expected.enum.name", t.values.mkString(", "))
    Reads.of[String].filter(validationError)(s ⇒ t.values.exists(v ⇒ v.toString == s)).map(t.withName(_))
}

implicit def enumerationValueSetReads(t: Enumeration): Reads[t.ValueSet] =
    Reads.seq(enumerationReads(t : t.type)).map(set => t.ValueSet(set : _*))

或者可能更有用

implicit def enumerationValueSetReads(t: Enumeration): Reads[Set[t.Value]] =
    Reads.set(enumerationReads(t : t.type))

枚举已经是一个对象(类Enumeration),因此您可以直接使用它。您不需要引入类型T。要正确键入函数,编译器必须检查ValueValueSet类型是否都属于Enumeration的正确实例(此处为t)。这称为path-dependent types

在以下代码中

class T extends Enumeration

object Animals extends T {
    val Cow, Pig, Rabbit = Value
}

object Food extends T {
    val Rice, Potatoes, Fries = Value
}

AnimalsFood都是T的实例,但T # ValueAnimals.ValueFood.Value类型不同。 T # Value代表Value任何实例的任何类型T,而Animals.Value(分别为Food.Value)属于Animals和{{ 1}}单独。

在错误&#34; Seq [t.Value]无法转换为Seq [t.Value]&#34;,我承认这非常令人困惑,Animals的两次出现是不同的实例。如果您使用t类型调用enumerationReads[T],则会将其参数T视为t的任何未知实例。所以你失去了实例的轨道。这就是您必须使用T类型调用它的原因。