我有以下特质:
sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
然后我定义了一个类型为Branch
的变量:
val t = Branch(Branch(Leaf("S"), Leaf(2)), Leaf(99))
上面的代码运行正常。但是当我把它改为:
val t = Branch[Int](Branch(Leaf("S"), Leaf(2)), Leaf(99))
编译器抱怨:
Error:(41, 37) type mismatch;
found : String("S")
required: Int
val t = Branch[Int](Branch(Leaf("S"), Leaf(2)), Leaf(99))
当我确定第一个Branch
上的类型时(在这种情况下是Int),那么节点将来自父节点?
答案 0 :(得分:4)
这里发生的是,在Branch(Leaf("S"), Leaf(2))
的情况下,编译器将尝试查找公共类型。对于Int
和String
,其超类型将为Any
。
问题是您使用Branch[Int]
强制分支定义中的类型,该类型由包含的Branch[Any]
无效。删除[Int]
将解决编译错误,但最终会导致Branch[Any]
。
让我们分析一下你的定义:
sealed trait Tree[+A]
此处+
表示类型A
可以是协变的。我不会详细介绍方差,因为有许多好的文章解释它(例如here)。基本上,这意味着如果String
是Any
的子类型,那么Tree[String]
将是Tree[Any]
的子类型。
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
让我们首先注意左侧树和右侧树中A
是如何出现的。那么当我们采用两种不同类型的树并将它们放在同一个分支中时会发生什么呢?
val left = Leaf(1) // Tree[Int]
val right = Leaf("a") // Tree[String]
val tree = Branch(left, right) // Tree[???]
由于A
和left
值中的right
必须相同(这就是我们定义它的方式),编译器会尝试解决此问题。所以它问自己:Int
和String
的第一种常见类型是什么?
Any
^
/ \
/ \
/ \
AnyVal AnyRef
/ \
Int String
\ /
...
这是Scala中的类型层次结构,非常简化。它更好地说明here。因此,String
和Int
的常见超类型为Any
,这就是您的树将成为Tree[Any]
的原因。