由于无法找到该问题,我感到非常惊讶。为什么这样,给定:
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]
找到适当的隐式转换的方式({{ 1}},我相信)。仅使用option2Iterable
,该类型已知且不正确,因此未尝试转换(并且p
没有转换Function1
返回Option
返回{{1} }})。
这个推理是对的吗?如果是这样,有什么理由我不应该将此报告为错误/问题吗?
编辑:一个新的转折:我看到Function1
在一些(遗憾的)删除的评论中提到了(虽然这是关于编码风格)。令人惊讶的是,它与GenTraversableOnce
一样有效。
答案 0 :(得分:8)
当你输入List(1, 2, 3).flatMap(p(_))
幕后所做的事情时,函数p
会被生成并包含在另一个部分应用它的函数中 - 这意味着所有必要的隐式转换(如果有的话)将会也可以在这个新函数的主体内部应用。
当您键入List(1, 2, 3).flatMap(p)
时,不会发生任何函数应用程序,并且您尝试传递与签名Int => Option[Int]
不兼容的Int => GenTraversableOnce[Int]
,尽管范围包含来自{的隐式转换{1}}至Option[T]
,未定义从Iterable[T]
到Function1[Int, Option[Int]]
的转换。
原因可能是因为任意arity的函数由于泛型而具有几乎无限的变化,并且由于Function1[Int, Iterable[Int]]
s不共享超级,所以每个都需要相当多的含义。功能类型。
这是一个扩展Function
的结构,足以实现flatMap
的预期结果。然而,它使p
已经模糊的签名更不清晰(更不清楚)。我相信,实现这种行为没有任何技术障碍,但签名的复杂性是scala-collections库经常受到欢迎的原因。
flatMap
答案 1 :(得分:4)
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)
对我而言,这不是一个错误,但我同意,它也不直观。