调用toSet丢失参数类型错误

时间:2012-10-27 05:02:26

标签: scala

为什么这段代码不起作用:

scala> List('a', 'b', 'c').toSet.subsets.foreach(e => println(e))

<console>:8: error: missing parameter type
              List('a', 'b', 'c').toSet.subsets.foreach(e => println(e))
                                                        ^

但是当我拆分它然后工作正常:

scala> val itr=List('a', 'b', 'c').toSet.subsets
itr: Iterator[scala.collection.immutable.Set[Char]] = non-empty iterator

scala> itr.foreach(e => println(e))
Set()
Set(a)
Set(b)
Set(c)
Set(a, b)
Set(a, c)
Set(b, c)
Set(a, b, c)

此代码也可以:

Set('a', 'b', 'c').subsets.foreach(e => println(e))

1 个答案:

答案 0 :(得分:6)

首先,有一个更简单的代码版本具有相同的问题:

List('a', 'b', 'c').toSet.foreach(e => println(e))

这不起作用

List('a', 'b', 'c').toBuffer.foreach(e => println(e))

然而,这些工作正常:

List('a', 'b', 'c').toList.foreach(e => println(e))
List('a', 'b', 'c').toSeq.foreach(e => println(e))
List('a', 'b', 'c').toArray.foreach(e => println(e))

如果你去查看List class documentation,你会看到有效的方法返回一些用A参数化的类型,而不起作用的方法返回用{{1}参数化的类型}}。问题是Scala编译器无法确定使用哪个B >: A!这意味着如果您告诉它类型它将起作用:

B

现在为什么 List('a', 'b', 'c').toSet[Char].foreach(e => println(e)) toSet有签名,我不知道......

最后,不确定这是否有用,但这也有效:

toBuffer

更新:稍微调试一下文档后,我注意到该方法适用于所有带有协变类型参数的类型,但带有< em> invariant 类型参数在返回类型中具有// I think this works because println can take type Any List('a', 'b', 'c').toSet.foreach(println) 。有趣的是,尽管{1}在Scala中是不变的,但它们提供了两个版本的方法(一个带有B >: A,另一个带有Array),这就是为什么它没有这个错误。

我也从未真正回答为什么将表达式分成两行。当您只是单独调用A时,编译器会自动将B >: A推断为toSet的结果A,除非您确实给它一个特定类型挑。这就是类型推断算法的工作原理。但是,当你将另一个未知类型抛入混合(即lambda中B的类型)时,推理算法会扼杀并死掉 - 它只能处理一个未知的{{ 1}}以及未知类型的Set[B]