为什么Scala在第一种情况下警告类型擦除而不是第二种情况?

时间:2011-08-22 19:41:20

标签: scala pattern-matching type-erasure

我有两个功能(这些功能自原版以来没有被编辑过 - 下面的一些答案是对原来那些回复了()序列的回答:

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (List(a, b) <- ls sliding 2) yield a

def foo2[A](ls: Iterable[A]) : Iterator[A] =
    for (a::b::Nil <- ls sliding 2) yield a
我天真地认为是相同的。但斯卡拉只对第一个减弱了这一点:

warning: non variable type-argument A in type pattern List[A]
is unchecked since it is eliminated by erasure

我想我理解为什么它会给第一个错误:Scala认为我正在尝试将该类型用作模式的条件,即如果B没有,则对List[B](_, _)的匹配应该失败继承自A,但这不会发生,因为在这两种情况下都会删除类型。

所以有两个问题:

1)为什么第二个没有给出相同的警告?

2)是否有可能说服Scala在编译时实际知道该类型,因此不可能无法匹配?

编辑:我认为this answers my first question。但我仍然对第二个感到好奇。

编辑:agilesteel在评论

中提到
for (List(a, b) <- List(1,2,3,4) sliding 2) yield ()

不会发出警告。与foo1有什么不同([Int]参数不应该与[A]参数一样被删除?

3 个答案:

答案 0 :(得分:4)

我不确定这里发生了什么,但Iterable[A].sliding的静态类型是Iterator[Iterable[A]],而不是Iterator[List[A]],它是List[A].sliding的静态类型。< / p>

您可以尝试接收Seq而不是Iterable,这也可以。 编辑与我之前声称的相反,IterableSeq都是共变体,所以我不知道有什么不同。 结束编辑 sliding的定义也很奇怪:

def sliding [B >: A] (size: Int): Iterator[Iterable[A]]

了解它如何需要一个永远不会被使用的B超级类A?与Iterator.sliding对比,没有问题:

def sliding [B >: A] (size: Int, step: Int = 1): GroupedIterator[B]

无论如何,第二个案例:

for (a::b::Nil <- ls sliding 2) yield a

在这里,您要对列表进行两次分解,对于每次分解,head的类型都会针对A进行检查。由于head的类型未被删除,因此您没有问题。这也是一个猜测。

最后,如果您将ls变为List,则不会出现问题。除此之外,我认为你无能为力。否则,你也可以这样写:

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (Seq(a, b) <- ls.iterator sliding 2) yield a

答案 1 :(得分:2)

1)第二个不会产生警告,可能是因为您正在构建列表(或模式),方法是将元素添加到Nil对象,该对象扩展List使用{{1}对其进行参数化}}。因为一切都是Nothing,所以没有什么可担心的;)但我不确定,真的在这里猜测。

2)你为什么不使用:

Nothing

答案 2 :(得分:0)

我对Scala并不是很熟悉,但是我已经使用过Java和Haskell了,所以我想在这里走出去,并猜测你的第二个例子并没有做同样的事情。看起来它们都使用模式匹配来解构列表的前两个元素,但第二个使用cons运算符而不是List构造函数。我的猜测是,这与Java的互操作有某种关系,并且List构造函数与cons运算符实际运行的方式之间存在细微差别。

另一方面,也许它只是一个被编译器忽略的边缘情况,它们都会产生警告。