Scala:使用协变 Field[+T] 访问属性

Scala: accessing properties using covariant Field[+T]

我正在使用一个自定义的不可变实体 class,它使用的键是扩展 Field[+T] 的 case 对象,其中 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
  }

}

然而,当我尝试检索 Byte 值并将其分配给 Int 字段时,这会导致编译错误。我知道 Byte 不是 Int 的子类型,它们唯一的关系是隐式转换。令我惊讶的是,在上面的示例中没有调用此转换,编译器现在要求我传递一个 Field[Int]!

经过一段时间的试验,我意识到我可以简单地明确提供类型,例如 val ageInt: Int = user[Byte](_age)。虽然这有效,但它使我的代码比我希望的更冗长。有什么办法可以更改 Entity.apply 的签名,使其符合 field 参数的类型?

def apply[T, U](field: Field[U])(implicit ev: U => T): T = 
  ev(attrs(field).asInstanceOf[U])

有效。