为什么编译器将t1 ++ t2结果视为List [Any]?连接两个S类型的列表应该只返回一个S类型的列表。
// compiles
def cons[S <: List[Any]](t1: S, t2: S): S = t1
// type mismatch; found List[Any] required S
def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
答案 0 :(得分:3)
以下是我认为正在发生的事情。首先,S
在任何地方都是相同的类型,这里没有魔力。让我们看一下第一个例子:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = if(t1.isEmpty) t1 else t2
cons: [S <: List[Any]](t1: S, t2: S)S
scala> cons(List(1), List(2.0))
res21: List[AnyVal] = List(2.0)
正如您所看到的,Scala正确地找到了Int
和Double
最接近的共同祖先,以及它AnyVal
。因此,在这种情况下,S
为AnyVal
。
现在让我们试试这个:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
<console>:11: error: type mismatch;
found : List[Any]
required: S
def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
^
出了什么问题?此错误消息表示++
的结果以某种方式List[Any]
而不是预期的S
。这是为什么?让我们看一下++
签名(简化,真实签名更长):
def ++[B >: A](other: List[B]): List[B] = ???
因此Scala需要找到A
的最近祖先和other
的实际类型参数。唯一的问题是:它需要在您定义B
的位置找到cons
,而不是在以后应用它的位置(B
不是cons
的免费参数) 。唯一的信息是S
及List[Any]
的上限,因此B
定义cons
的唯一安全解决方案是最通用的,即Any
。这意味着++
的结果为List[Any]
,并且它不适合S
。因此错误。
第三个例子:
scala> def cons[S <: Any](t1: List[S], t2: List[S]): List[S] = t1 ++ t2
cons: [S](t1: List[S], t2: List[S])List[S]
scala> cons(List(1), List(1.0))
res0: List[AnyVal] = List(1, 1.0)
为什么这样做?这里t1
和t2
具有完全相同的类型,无论S
是什么(以后可以推断出S
)。所以B == S
,结果是List[S]
。同样在这种特殊情况下,S
是Int
和Double
最接近的共同祖先。
答案 1 :(得分:1)
List[Any] ++ List[Any]
是List[Any]
并不保证S
,List[Any]
的子类型也具有S ++ S
的属性S
,所以编译器会回到List[Any]
。