涉及case语句和类型成员的Scala类型推断

时间:2011-12-12 17:24:16

标签: scala type-inference

对不起,但我想不出更好的标题(建议欢迎)。

基本上我有一个类层次结构,子类有一个类型成员,表示“它们应该映射到哪种类型”。然后我想要一个为这些类型实现某种异构映射的类。请参阅以下代码作为示例。

我的问题是我是否(以及如何)在不诉诸演员的情况下将其付诸实践。如果它不起作用,请解释原因。

trait A {
  type Result
}

case class AInt(id: String) extends A {
  type Result = Int
}

case class AString(id: String) extends A {
  type Result = String
}

class AStore {
  val mapInt = new collection.mutable.HashMap[String,Int]()
  val mapString = new collection.mutable.HashMap[String,String]()

  def put[T <: A](t: T, result: T#Result) {
    t match {
      case AInt(id) => mapInt(id) = result
      case AString(id) => mapString(id) = result
    }
  }

  def get[T <: A](t: T): T#Result = t match {
    case AInt(id) => mapInt(id)
    case AString(id) => mapString(id)
  }
}

尝试编译它会产生以下错误消息:

19: error: type mismatch;
 found   : T#Result
 required: Int
      case AInt(id) => mapInt(id) = result
                                    ^
20: error: type mismatch;
 found   : T#Result
 required: String
      case AString(id) => mapString(id) = result
                                          ^
25: error: type mismatch;
 found   : Int
 required: T#Result
    case AInt(id) => mapInt(id)
                           ^
26: error: type mismatch;
 found   : String
 required: T#Result
    case AString(id) => mapString(id)
                                 ^
four errors found

1 个答案:

答案 0 :(得分:3)

这不是一个简单的原因:在

  def put[T <: A](t: T, result: T#Result) {
    t match {
      case AInt(id) => mapInt(id) = result
      case AString(id) => mapString(id) = result
    }
  }

T的范围是整个方法定义,因此您不能在不同的分支中使用不同的T#Result

您可以查看GADTs

这是链接帖子给出的编码的例子:

trait A[Result] {
  def id: String
}

case class AInt(id: String) extends A[Int]

case class AString(id: String) extends A[String]

class AStore {
  val mapInt = new collection.mutable.HashMap[String,Int]()
  val mapString = new collection.mutable.HashMap[String,String]()

  def put[Result](t: A[Result], result: Result) {
    t match {
      case AInt(id) => mapInt(id) = result
      case AString(id) => mapString(id) = result
    }
  }

  def get[Result](t: A[Result]): Result = t match {
    case AInt(id) => mapInt(id)
    case AString(id) => mapString(id)
  }
}