map
和flatMap
首先flatMap
是高阶函数。
map
也是一个高阶函数,它将通过对 a的所有元素应用函数来将 a 转换List
为新函数。例如,如果您有List
List
val l = List(1,2,3)
您可以map
使用它到一个新列表
val doubled = l.map(_ * 2) // List(2,4,6)
那么是什么flatMap
?flatMap
当您的函数获取 aInt
但返回 a时很有用List[Int]
。在这种情况下,如果你将这个函数传递给map
你得到的将是 aList[List[Int]]
但有时你想得到 a List[Int]
。
你能做的就是flatMap
改用。从数学上讲,它相当于 firstmap
然后flatten
是结果,但实际上它可能flatten
是基于而flatMap
不是相反的方式定义的函数。
抛开技术细节不谈,flatten
意味着如果你有一个List[List[List...[Int]]]
,如果你flatten
有,你就会得到一个List[Int]
。
当我们看
def flatten(l: List[Any]): List[Any] = l flatMap {
case ms:List[_] => flatten(ms)
case l => List(l)
}
我们首先需要知道这意味着什么。我们已经知道我们必须将一个函数传递给flatMap
. 在这种情况下,我们传递的函数是
{
case ms:List[_] => flatten(ms)
case l => List(l)
}
起初看起来不像是一个功能,但它是!它实际上是一个偏函数,您可以将其视为具有一些细微差别的函数!
什么是偏函数?
我们可以通过以下方式实现(几乎)相同的结果:
def flatten(l: List[Any]): List[Any] = l flatMap { _ match {
case ms:List[_] => flatten(ms)
case l => List(l)
}
}
普通函数和偏函数的区别在于,对于某些特定的输入,偏函数可能是未定义的。所以编译器会自动从以关键字开头的主体生成部分函数case
(这不是那么简单,但为了简单起见,我在这里跳过细节)。
按类型匹配模式
类似的模式ms:List[_]
称为类型模式。这意味着ms
将在运行时针对List[_]
. _
是一个通配符,表示任何类型,因此ms:List[_]
字面意思是List
任何类型的 a(由于类型擦除,您不能使用类似 的模式ms:List[Int]
,请参阅此线程以获取更多信息)。
所以这个代码片段上的整个模式匹配意味着
- 如果
ms
是列表,结果将是flatten(ms)
,否则结果将是List(l)
。
像这样定义的flatten
函数是递归函数,它解包列表并执行此操作直到没有更多列表,然后它将再次将结果包装在List
! 这种方式List[List[List.......[_]]]
将转换为List[_]
.
类型模式的另一个示例:
def hello(o: Any) = o match {
case _:Int => "Hi, I am an Int and I'm proud of it!"
case _:List[_] => "I have many things to tell you! I am a list after all!"
case b:Boolean => s"I'm simply a flag and my value is $b"
case _ => "I'm everything else you can imagine :D"
}
消歧义
顺便说一下,部分函数与部分应用函数和部分应用完全不同!
Scala 中偏函数的概念与数学中的偏函数相同:一个函数,对于其域的某些值可能是未定义的。