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

时间:2016-10-09 11:27:21

标签: scala compiler-errors functional-programming covariance

我使用自定义不可变实体类,它使用作为案例对象的键,扩展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参数的类型?

1 个答案:

答案 0 :(得分:4)

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

的工作原理。