我尝试在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免费?
答案 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
。要正确键入函数,编译器必须检查Value
和ValueSet
类型是否都属于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
}
Animals
和Food
都是T
的实例,但T # Value
,Animals.Value
和Food.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
类型调用它的原因。