[英]Can't get path-dependent types to work in scala enumerations
I'm trying to spin my head around the path-dependent types in Scala's enums while making a Reads/Writes for Play2. 我试图在为Play2进行读/写操作时围绕Scala枚举中与路径相关的类型进行操作。 Here is the code I have so far, it works, but with an asInstanceOf: 这是我到目前为止的代码,它可以工作,但是带有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]]: _*))
What can I do to get rid of the asInstanceOf on the last line? 我该怎么做才能摆脱最后一行中的asInstanceOf? I tried typing the enumerationReads as enumerationReads[t.Value], but that doesn't work, the compiler complains in the argument of t.ValueSet that Seq[t.Value] cannot be cast to Seq[t.Value]. 我尝试将enumerationReads键入为enumerationReads [t.Value],但这没有用,编译器在t.ValueSet的参数中抱怨Seq [t.Value]无法转换为Seq [t.Value]。 Yes, that didn't make sense to me too, until I started to realize these different t's might actually be different, since they are used in a closure. 是的,这对我来说也没有意义,直到我开始意识到这些不同的t实际上可能有所不同,因为它们是在闭包中使用的。
So, what to do to make my code super-duper asInstanceOf free? 那么,该怎么做才能使我的代码超级重复asInstanceOf自由呢?
The following code might do the trick: 以下代码可以解决问题:
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 : _*))
or maybe more useful 也许更有用
implicit def enumerationValueSetReads(t: Enumeration): Reads[Set[t.Value]] =
Reads.set(enumerationReads(t : t.type))
An enumeration is already an object (of class Enumeration
) so you can use it directly. 枚举已经是( Enumeration
类的)对象,因此您可以直接使用它。 You don't need to introduce a type T
. 您不需要引入类型T
To type your functions correctly the compiler has to check that types Value
and ValueSet
both belong to the correct instance of Enumeration
(here t
). 为了正确键入函数,编译器必须检查类型Value
和ValueSet
都属于Enumeration
的正确实例(此处为t
)。 That's called path-dependent types . 这就是依赖于路径的类型 。
In the following code 在下面的代码中
class T extends Enumeration
object Animals extends T {
val Cow, Pig, Rabbit = Value
}
object Food extends T {
val Rice, Potatoes, Fries = Value
}
Both Animals
and Food
are instances of T
but the types T # Value
, Animals.Value
and Food.Value
are different. Animals
和Food
都是T
实例,但是类型T # Value
, Animals.Value
和Food.Value
不同。 T # Value
represent any type Value
of any instance of T
whereas Animals.Value
(respectively Food.Value
) is the type that belongs to Animals
and Animals
alone. T # Value
表示任何类型的Value
的任何实例的T
而Animals.Value
(分别Food.Value
)是属于所述类型Animals
和Animals
独自。
In the error "Seq[t.Value] cannot be cast to Seq[t.Value]", which i admit is very confusing, the two occurences of t
are different instances. 我承认错误“无法将Seq [t.Value]强制转换为Seq [t.Value]”,这是非常令人困惑的, t
的两次出现是不同的实例。 If you call enumerationReads[T]
with type T
, it considers its argument t
to be any, unknown, instance of T
. 如果你打电话enumerationReads[T]
类型T
,它认为它的参数t
是任意的,未知的情况下T
。 So you lose the track of the instance. 因此,您会失去实例的踪迹。 That's why you have to call it with type t.type
. 这就是为什么必须使用类型t.type
来调用它的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.