2017-03-16 213 views
0

我具有以下特征:类型参数的类型不匹配

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),那么节点将固有的家长吗?

回答

4

这里发生的是,在Branch(Leaf("S"), Leaf(2))的情况下,编译器将尝试找到一个通用类型。在IntString的情况下,它们的超类型将是Any

问题在于,您正在使用Branch[Int]强制使用分支定义中的类型,该分类被包含的Branch[Any]无效。删除[Int]将修复编译错误,但最终会得到Branch[Any]

让我们来细数了一下你的定义:

sealed trait Tree[+A] 

+在这里说,类型A可协变。我不会详细介绍差异,因为有很多很好的文章解释它(例如here)。基本上这意味着如果StringAny的子类型,那么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必须在leftright值相同(这就是我们如何定义它),编译器试图解决这个问题。所以它问自己:IntString的第一种常见类型是什么?

 Any 
     ^
    /\ 
    / \ 
    / \ 
AnyVal  AnyRef 
/  \ 
    Int  String 
    \  /
     ... 

这是Scala中的类型层次结构相当简化。这是更好地说明here。因此,StringInt的常见超类型是Any,这就是为什么您的树将是Tree[Any]

+0

因此,当我不强制使用适当的类型时,任何类型的'Any'都会被使用。 –

+0

不,第一种常见的类型将被使用。在这种情况下,它是“任何”。 –

+0

当我强制类型是一个'Int',那么所有类型的节点和叶子将是'Int'?它会从分支固有吗? –