3

为什么编译器将 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 
4

2 回答 2

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 正确地找到了 and 最接近的共同祖先IntDouble并且它是AnyVal. 所以在这种情况下SAnyVal

现在让我们试试这个:

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] = ???

A所以Scala 需要找到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最接近的共同祖先。IntDouble

于 2016-08-20T02:38:43.387 回答
1

List[Any] ++ List[Any]is aList[Any]不保证S,a 的子类型List[Any]也有S ++ Sis a的属性S,所以编译器回退到List[Any].

于 2016-08-19T23:30:37.623 回答