为什么这个flatMap失败了?

时间:2013-03-12 06:30:08

标签: scala

scala> val s: Seq[Class[_ <: java.lang.Enum[_]]] = Seq(classOf[java.util.concurrent.TimeUnit])
s: Seq[Class[_ <: java.lang.Enum[_]]] = List(class java.util.concurrent.TimeUnit)

scala> s.flatMap(_.getEnumConstants)
<console>:9: error: no type parameters for method flatMap: (f: Class[_ <: java.lang.Enum[_]] => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Class[_ <: java.lang.Enum[_]]],B,That])That exist so that it can be applied to arguments (Class[_ <: java.lang.Enum[_]] => scala.collection.mutable.ArrayOps[_$1(in value $anonfun) with java.lang.Object] forSome { type _$1(in value $anonfun) <: java.lang.Enum[_] })
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Class[_ <: java.lang.Enum[_]] => scala.collection.mutable.ArrayOps[_$1(in value $anonfun) with java.lang.Object] forSome { type _$1(in value $anonfun) <: java.lang.Enum[_] }
 required: Class[_ <: java.lang.Enum[_]] => scala.collection.GenTr...              s.flatMap(_.getEnumConstants)

2 个答案:

答案 0 :(得分:6)

不是确切的答案,但有两个观察 - Scala 2.10会给你一个更好的错误:

scala> s.flatMap(_.getEnumConstants)
<console>:9: error: no type parameters for method flatMap: (f: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Class[_ <: Enum[_]]],B,That])That exist so that it can be applied to arguments (Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] })
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] }
 required: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[?B]
              s.flatMap(_.getEnumConstants)
                ^
<console>:9: error: type mismatch;
 found   : Class[_ <: Enum[_]] => scala.collection.mutable.ArrayOps[(some other)_$1(in object $iw) with Object] forSome { type (some other)_$1(in object $iw) <: Enum[_] }
 required: Class[_ <: Enum[_]] => scala.collection.GenTraversableOnce[B]
              s.flatMap(_.getEnumConstants)
                          ^
<console>:9: error: Cannot construct a collection of type That with elements of type B based on a collection of type Seq[Class[_ <: Enum[_]]].
              s.flatMap(_.getEnumConstants)
                   ^

而且,如果你拆分flatMap,你会看到一个更简单的问题版本:

scala> s.map(_.getEnumConstants)
res28: Seq[Array[_$1 with Object] forSome { type _$1 <: Enum[_] }] = List(Array(NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS), Array(RELEASE_0, RELEASE_1, RELEASE_2, RELEASE_3, RELEASE_4, RELEASE_5, RELEASE_6))
scala> res28.flatten
<console>:10: error: No implicit view available from Array[_$1 with Object] forSome { type _$1 <: Enum[_] } => scala.collection.GenTraversableOnce[B].
              res28.flatten
                    ^

这是相当令人惊讶的,因为您认为将Array转换为GenTraversableOnce应该很容易。我现在没有时间挖掘细节,但我会指出以下事情似乎有效:

s.flatMap(_.getEnumConstants.toSeq)
s.flatMap(_.getEnumConstants.map(_.asInstanceOf[Enum[_]]))

我投票编译错误,因为this gist,这显示了这个简单脚本的REPL中一些非常奇怪的行为

val s: Seq[Class[_ <: java.lang.Enum[_]]] = Seq(classOf[java.util.concurrent.TimeUnit], classOf[javax.lang.model.SourceVersion])
s.flatMap(_.getEnumConstants.toSeq)
s.flatMap(_.getEnumConstants.toArray)
1234

答案 1 :(得分:2)

TimeUnit.getEnumConstants返回一个java数组TimeUnit[],而flatMap需要一个GenTraversable

你可以使用

scala> s.flatMap(_.getEnumConstants.toSeq)
res4: Seq[Enum[_]] = List(NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS)