我很惊讶没能找到这个问题的答案。为什么呢,因为:
val p: Int => Option[Int] = Some(_)
List(1, 2, 3).flatMap(p)我得到了:
<console>:14: error: type mismatch;
found : Int => Option[Int]
required: Int => scala.collection.GenTraversableOnce[?]
List(1, 2, 3).flatMap(p)但是,如果我用这一行替换最后一行,它就会像预期的那样编译和工作:
List(1, 2, 3).flatMap(p(_))我对这个问题的看法是,在p(_)的情况下,类型推理系统会启动来决定lambda的类型,以及它如何为Option[Int]找到适当的隐式转换(我相信是option2Iterable)。仅使用p,类型已经已知,并且它是不正确的,因此不尝试转换(而且Function1返回Option到Function1返回GenTraversableOnce也没有转换)。
这个推论对吗?如果是这样的话,有什么理由我不应该报告这是一个错误/问题?
编辑:一个新的转折:我在一些(遗憾的)被删除的评论中提到了p.apply (尽管这是关于编码风格的)。令人惊讶的是,它的工作效果与p(_)一样好。
发布于 2016-06-09 13:02:52
当您输入List(1, 2, 3).flatMap(p(_))时,在幕后所做的就是在另一个部分应用它的函数中生成和包装p --这意味着所有必要的隐式转换(如果有的话)也将在这个新函数的主体中应用。
当您键入List(1, 2, 3).flatMap(p)时,不会发生函数应用程序,您将尝试传递一个与签名Int => GenTraversableOnce[Int]不兼容的Int => Option[Int],尽管该作用域包含从Option[T]到Iterable[T]的隐式转换,但没有从Function1[Int, Option[Int]]到定义的Function1[Int, Iterable[Int]]的转换。
这可能是因为任意的函数由于泛型而几乎有无穷大的变化,而且由于Functions不共享一个超特性,这就需要对每种类型的函数都进行大量的关联。
下面是一个扩展flatMap以实现p所需结果的构造。然而,它使得已经模糊的flatMap签名更加不清晰(更不清楚)。我相信,实现这种行为没有技术障碍,但是签名的复杂性是scala集合库经常受到欢迎的原因。
import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
implicit class ListEx[A](list: List[A]) {
def flatMap2[B, M[_], That](f: A => M[B])
(implicit bf: CanBuildFrom[List[A], B, That],
view: M[B] => GenTraversableOnce[B]): That =
list.flatMap(f andThen view)
}
val p: Int => Option[Int] = Some(_)
List(1, 2, 3) flatMap2 p发布于 2016-06-09 13:11:53
List(1, 2, 3).flatMap(p(_))汇编如下:
List(1,2,3).flatMap(x => p(x))当p(x)返回时,Option[Int]和flatMap需要GenTraversableOnce[Int],所以应用了scala.Option.option2Iterable。
选项不继承GenTraversableOnce。要使此语法工作:
List(1,2,3).flatMap(p)您需要从Int => Option[Int]到Int => GenTraversableOnce[Int]的隐式转换,如下所示:
import scala.collection.GenTraversableOnce
implicit def conv(c: Int => Option[Int]): Int => GenTraversableOnce[Int] = {
a => Option.option2Iterable(c(a))
}
val p: Int => Option[Int] = Some(_)
List(1, 2, 3).flatMap(p)对我来说,这不是一个bug,但我同意,这也不是直观的。
https://stackoverflow.com/questions/37725975
复制相似问题