使用'type'关键字和路径相关类型覆盖类型

时间:2014-01-23 11:01:09

标签: scala types

让我说我有这样的代码和平:

trait  Holder  {
  type Value
  def put(v:Value)
}

class JsonHolder extends Holder {
  override type Value = String
  def put(v: JsonHolder.this.Value): Unit = {}
}

class XmlHolder extends Holder {
  override type Value = String
  def put(v: XmlHolder.this.Value): Unit = {}
}

object Foo {
  def main(args: Array[String]) {
    val jsonHolder = new JsonHolder
    val xmlHodler = new XmlHolder
    val valueOfJson = new jsonHolder.Value("AAA")
    val valueOfXml = new xmlHodler.Value("AAA")
    jsonHolder.put(valueOfXml)
  }
}

我不明白为什么这会编译。 jsonHolder.put(valueOfXml)不应该出现类型错误吗?

如果我改变

type Value

这样的事情:

case class Value(content:String)

并删除覆盖线,其他所有内容都会保留,因为它实际上会出现类型不匹配错误。

那么这两者之间的区别是什么,因为put参数的声明不必改变,行为完全不同?

2 个答案:

答案 0 :(得分:5)

嗯,这不是类型错误,因为JsonHolder.ValueXmlHolder.Value都是String。考虑type其他类型的别名。所有类型都被替换为实际类型。所以你的代码大致如下:

val valueOfJson = new String("AAA") // JsonHolder.Value is a String
val valueOfXml = new String("AAA") // XmlHolder.Value is a String as well

就像这样:

class JsonHolder extends Holder {
  def put(v: String): Unit = {}
}

class XmlHolder extends Holder {
  def put(v: String): Unit = {}
}

如果你的某个类型是Int,那么确定你会收到编译错误:

class JsonHolder extends Holder {
  override type Value = Int
  def put(v: JsonHolder.this.Value): Unit = {}
}

class XmlHolder extends Holder {
  override type Value = String
  def put(v: XmlHolder.this.Value): Unit = {}
}

object Foo {
  def main(args: Array[String]) {
    val jsonHolder = new JsonHolder
    val xmlHodler = new XmlHolder
    //compilation error here - Int doesn't have a String constructor
    val valueOfJson = new jsonHolder.Value("AAA") 
    val valueOfXml = new xmlHodler.Value("AAA")
    jsonHolder.put(valueOfXml)
  }
}

答案 1 :(得分:1)

我不是语言律师,但在我看来,Scala中的type可以说是别名类型的声明,因此在您的代码中,{{1}和JsonHolder.Value实际上都是相同的类型,即XmlHolder.ValueString(或new jsonHolder.Value(...))相当于new xmlHolder.Value(...),因此new String(...)并且valueOfJson都被推断为valueOfXml s。由于StringJsonHolder.put都采用单个String参数,因此代码类型检查。

但是,一旦用案例类替换XmlHolder.put,JsonHolder.Value和XmlHolder.Value就不再是路径依赖类型的规则。现在put函数不再具有相同的签名,并且值也具有不同的类型,因此类型不匹配错误。