7

このコードが機能しない理由:

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)

そして、このコードもOKです:

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

1 に答える 1

7

まず、同じ問題を持つコードのより単純なバージョンがあります。

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クラスのドキュメントを見ると、機能するメソッドは でパラメーター化された型を返すのAに対し、機能しないメソッドは でパラメーター化された型を返すことがわかりますB >: A。問題は、Scala コンパイラがどちらBを使用するか判断できないことです! つまり、タイプを指定すると機能します。

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

なぜ toSetその署名をtoBuffer持っているのか、私にはわかりません...

最後に、これが役立つかどうかはわかりませんが、これも機能します。

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

更新:ドキュメントをもう少し調べたところ、共変型パラメーターを持つすべての型でメソッドが機能することに気付きましたが、不変型パラメーターを持つ型B >: Aには戻り値の型があります。興味深いことに、ArrayScala では は不変ですが、メソッドの 2 つのバージョン (1 つは を使用しA、もう 1 つは を使用B >: A) を提供しているため、そのエラーは発生しません。

また、式を 2 行に分割することが機能する理由についても、実際には答えていません。単にtoSet独自に呼び出すと、コンパイラは、選択する特定の型を指定しない限り、結果の型のように自動的に推論Aします。これは、型推論アルゴリズムがどのように機能するかです。ただし、別の不明な型 (つまり、ラムダの の型) を混在させると、推論アルゴリズムが停止して停止します。つまり、未知の型と不明な型のを同様に処理できません。BSet[B]eB >: Ae

于 2012-10-27T05:53:17.313 に答える