我有两个功能(这些功能自原版以来没有被编辑过 - 下面的一些答案是对原来那些回复了()序列的回答:
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]
参数一样被删除?
答案 0 :(得分:4)
我不确定这里发生了什么,但Iterable[A].sliding
的静态类型是Iterator[Iterable[A]]
,而不是Iterator[List[A]]
,它是List[A].sliding
的静态类型。< / p>
您可以尝试接收Seq
而不是Iterable
,这也可以。 编辑与我之前声称的相反,Iterable
和Seq
都是共变体,所以我不知道有什么不同。 结束编辑 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运算符实际运行的方式之间存在细微差别。
另一方面,也许它只是一个被编译器忽略的边缘情况,它们都会产生警告。