首先,map
将x => x
视为与identity
List(1,2,3).map(x => x) //res0: List[Int] = List(1, 2, 3)
List(1,2,3).map(identity) //res1: List[Int] = List(1, 2, 3)
现在让我们将List [Option [Int]]转换为List [Int],丢弃所有None。我们可以通过.flatten
来做到这一点。但问题的关键是要了解flatMap
如何对待identity
val maybeNums = List(Some(1), None, Some(-2), None, None, Some(33))
// Works OK, result = List[Int] = List(1, -2, 33)
maybeNums.flatMap(x => x)
maybeNums.flatMap(x => x.map(identity))
// Not working:
maybeNums.flatMap(identity)
Error:(5, 20) type mismatch;
found : Option[Int] => Option[Int]
required: Option[Int] => scala.collection.GenTraversableOnce[?]
问题:为什么maybeNums.flatMap(identity)
在maybeNums.flatMap(x => x)
正常工作时会发出编译错误?
答案 0 :(得分:4)
有趣的是我遇到了类似的问题。这种行为是由GenTraversableOnce
不是GenTraversableOnce
但是存在隐式转换的事实引起的。编译器通知你出了什么问题,但不幸的是,在Scala中经常出现这种情况并不能指出错误的真正原因。如果您的集合包含ys.flatMap(identity(_))
类型的元素,则flatMap方法可以正常工作。
起初我认为隐式转换可以解决这个问题,但事实证明,eta扩展需要明确匹配的类型。更有趣的是以下代码编译:
Option[Int] => Option[Int]
我认为在这种情况下会发生从Option[Int] => GenTraversableOnce[Int]
到x => x
的隐式转换。
如果x
右unpivot
被转换为前面提到的隐式转换,那么代码编译
答案 1 :(得分:2)
对Lampart答案的更详细解释。
归结为类型推断在Scala中的工作原理以及预期类型的使用。
要使maybeNums.flatMap(???)
生效,???
必须包含Option[Int] => GenTraversableOnce[?A]
类型(其中?A
代表某种未知类型)。这是预期的类型。
当???
是像x => x
这样的lambda表达式时,参数的类型为Option[Int]
,并且主体的类型为GenTraversableOnce[?A]
。没有期望类型的正文的类型为Option[Int]
,因此会找到并插入从Option[Int]
到GenTraversableOnce[Int]
的隐式转换。
当???
为identity
时,对于某些未知类型identity[?B]
(与上面?B
相同的意义上的?A
,它是?B => ?B
的缩写,但它们不是当然,必须是相同的,因此类型?B => ?B == Option[Int] => GenTraversableOnce[?A]
也是如此。因此编译器需要解决具有两种未知类型的等式:?B = Option[Int]
。它匹配参数类型以选择?B
的{{1}},但无法找到合适的?A
。打印错误时,?B
被替换,我在上面?A
写的类型打印为?
(因为它是唯一剩下的未知数)。
如果identity(_)
,它会扩展为x => identity(x)
。同样,参数的类型推断为Option[Int]
,正文已计算出类型Option[Int]
和预期类型GenTraversableOnce[?A]
。