我使用自定义不可变实体类,它使用作为案例对象的键,扩展Field [+ T],其中T是协变的。这是有道理的,因为Field [Stream [Int]]应该能够被视为Field [Seq [Int]]。
object ProblemWithCovariant {
sealed trait Field[+T]
case object _username extends Field[String]
case object _email extends Field[String]
case object _age extends Field[Byte]
case class Entity(attrs: Map[Field[Any], Any]) {
def apply[T](field: Field[T]): T = attrs(field).asInstanceOf[T]
def set[T](field: Field[T])(value: T): Entity = copy(attrs = attrs.updated(field, value))
}
def main(args: Array[String]): Unit = {
val user = Entity(Map.empty)
.set(_username)("John")
.set(_age)(23)
val username: String = user(_username) // alright
val ageInt: Int = user(_age) // compile error
}
}
但是当我尝试检索字节值并将其分配给Int字段时,这会导致编译错误。我知道Byte不是Int的子类型,它们唯一的关系是隐式转换。令我惊讶的是,在上面的例子中没有调用这个转换,编译器现在要求我传递一个Field [Int]!
经过一段时间的实验,我意识到我可以简单地提供类型,例如val ageInt: Int = user[Byte](_age)
。虽然这有效,但它使我的代码比我想要的更冗长。有没有办法可以更改Entity.apply
的签名,使其尊重field
参数的类型?
答案 0 :(得分:4)
def apply[T, U](field: Field[U])(implicit ev: U => T): T =
ev(attrs(field).asInstanceOf[U])
的工作原理。