调用toSet丢失参数类型错误

Ole*_*liv 6 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))
                                                        ^
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

这段代码也可以:

Set('a', 'b', 'c').subsets.foreach(e => println(e))
Run Code Online (Sandbox Code Playgroud)

Dao*_*Wen 6

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

List('a', 'b', 'c').toSet.foreach(e => println(e))
Run Code Online (Sandbox Code Playgroud)

这也不起作用

List('a', 'b', 'c').toBuffer.foreach(e => println(e))
Run Code Online (Sandbox Code Playgroud)

但是,这些工作正常:

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))
Run Code Online (Sandbox Code Playgroud)

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

List('a', 'b', 'c').toSet[Char].foreach(e => println(e))
Run Code Online (Sandbox Code Playgroud)

至于为什么 toSettoBuffer有这个签名,我不知道......

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

// I think this works because println can take type Any
List('a', 'b', 'c').toSet.foreach(println)
Run Code Online (Sandbox Code Playgroud)

更新:在更多地讨论文档后,我注意到该方法适用于所有具有协变类型参数的类型,但具有不变类型参数的类型具有B >: A返回类型.有趣的是,尽管Array在Scala中它们是不变的,但它们提供了两个版本的方法(一个带有A一个和一个带有B >: A),这就是为什么它没有那个错误.

我也从未真正回答为什么将表达式分成两行.当你简单地调用toSet自身,编译器会自动推断AB在所导致的类型Set[B],除非你给它一个特定的类型来挑选.这就是类型推断算法的工作原理.但是,当你将另一个未知类型抛入混合(即elambda中的类型)时,推理算法会扼杀和死亡 - 它也无法处理B >: A未知类型和未知类型e.