让我说我有这样的代码和平:
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参数的声明不必改变,行为完全不同?
答案 0 :(得分:5)
嗯,这不是类型错误,因为JsonHolder.Value
和XmlHolder.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.Value
和String
(或new jsonHolder.Value(...)
)相当于new xmlHolder.Value(...)
,因此new String(...)
并且valueOfJson
都被推断为valueOfXml
s。由于String
和JsonHolder.put
都采用单个String参数,因此代码类型检查。
但是,一旦用案例类替换XmlHolder.put
,JsonHolder.Value和XmlHolder.Value就不再是路径依赖类型的规则。现在put函数不再具有相同的签名,并且值也具有不同的类型,因此类型不匹配错误。