【问题标题】:missing parameter type error by calling toSet通过调用 toSet 丢失参数类型错误
【发布时间】:2012-10-17 08:05:43
【问题描述】:

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

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))

【问题讨论】:

标签: scala


【解决方案1】:

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

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 参数化的类型,而不起作用的方法返回用B &gt;: A 参数化的类型。问题是 Scala 编译器无法确定使用哪个B!这意味着如果你告诉它类型它就会起作用:

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

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

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

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

更新: 在浏览了更多文档之后,我注意到该方法适用于所有带有 covariant 类型参数的类型,但那些带有 invariant 类型参数在返回类型中有B &gt;: A。有趣的是,虽然 Array 在 Scala 中是不变的,但它们提供了两种版本的方法(一种带有 A,另一种带有 B &gt;: A),这就是它没有该错误的原因。

我也从未真正回答过为什么将表达式分成两行有效。当您简单地单独调用toSet 时,编译器将自动将A 推断为生成Set[B] 的类型中的B,除非您确实给它指定了要选择的特定类型。这就是类型推断算法的工作原理。但是,当您将 另一个 未知类型(即您的 lambda 中的 e 类型)添加到混合中时,推理算法就会窒息而死——它无法处理未知的 B &gt;: Ae 的未知类型。

【讨论】:

    猜你喜欢
    • 2012-10-19
    • 2012-05-22
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    相关资源
    最近更新 更多