1. 偏函数
1.1 问题引入
给你一个集合val list = List(1, 2, 3, 4, “abc”) ,请完成如下要求:
- 将集合list中的所有数字+1,并返回一个新的集合
- 要求忽略掉 非数字 的元素,即返回的 新的集合 形式为 (2, 3, 4, 5)
- 解决方式一
val list = List(1,2,3,4,"abc")
def f1(n : Any): Boolean = {
n.isInstanceOf[Int]
}
def f2(n : Any): Int = {
n.asInstanceOf[Int]
}
def f3(n: Int) : Int = {
n + 1
}
list.filter(f1).map(f2).map(f3)
- 解决方式二: 模式匹配
val list = List(1,2,3,4,"abc")
def addOne(i : Any): Any = {
i match {
case x : Int => x + 1
case _ =>
}
}
list.map(addOne)
- 使用偏函数
val list1: List[Int] = list.collect {
case i: Int => i + 1
}
1.2 偏函数
- 在
对符合某个条件,而不是所有情况进行逻辑操作时,使用偏函数
是一个不错的选择- 将包在
大括号内的一组case语句封装为函数
,我们称之为偏函数,它只对会作用于指定类型的参数或指定范围值的参数
实施计算,超出范围的值会忽略.- 偏函数在Scala中是一个特质PartialFunction
2. 作为参数的函数
3. 闭包
3.1 闭包入门
- 基本介绍:闭包就是一个函数和与其相关的引用环境(变量/值)组合的一个整体(实体)。
def minusxy(x: Int) = (y: Int) => x – y
//minusxy 他会返回一个匿名函数 (y: Int) => x – y
//匿名函数,他使用了一个外部的变量 x
//f函数就是闭包.
val f: Int => Int = minusxy(20)
println("f(1)=" + f(1))
println("f(2)=" + f(2))
- 代码小结
(1) (y: Int) => x – y
返回的是一个匿名函数 ,因为该函数引用到到函数外的 x,那么 该函数和x整体形成一个闭包
如:这里 val f = minusxy(20) 的f函数就是闭包
(2) 可以这样理解,返回函数是一个对象,而x就是该对象的一个字段,他们共同形成一个闭包
(3) 当多次调用f时(可以理解多次调用闭包),发现使用的是同一个x, 所以x不变。
(4)在使用闭包时,主要搞清楚返回函数引用了函数外的哪些变量,因为他们会组合成一个整体(实体),形成一个闭包
3.2 闭包案例
请编写一个程序,具体要求如下
- 编写一个函数 makeSuffix(suffix: String) 可以接收一个文件后缀名(比如.jpg),并返回一个闭包
- 调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg) ,则返回 文件名.jpg , 如果已经有.jpg后缀,则返回原文件名。
- 要求使用闭包的方式完成
- String.endsWith(xx)
def makeSuffix(suffix: String): String => String = {
(filename : String)=> {
if (filename.endsWith(suffix)){
filename
}else{
filename + suffix
}
}
}
val file: String => String = makeSuffix(".jpg")
val filename: String = file("jdj")
val filename2: String = file("xxx.jpg")
3.3 闭包的优势
- 返回的匿名函数和 makeSuffix (suffix string) 的 suffix 变量 组合成一个闭包,因为返回的函数引用到suffix这个变量
- 体会一下闭包的好处,如果使用传统的方法,也可以轻松实现这个功能,但是传统方法需要每次都传入后缀名,比如 .jpg ,而闭包因为可以保留上次引用的某个值,所以我们传入一次就可以反复使用。大家可以仔细的体会一把
4. 柯里化
编写一个函数,接收两个整数,可以返回两个数的乘积,要求:
- 使用常规的方式完成
- 使用闭包的方式完成
- 使用函数柯里化完成
def mul(x: Int, y: Int) = x * y
println(mul(10, 10))
def mulCurry(x: Int) = (y: Int) => x * y
println(mulCurry(10)(9))
def mulCurry2(x: Int)(y:Int) = x * y
println(mulCurry2(10)(8))
// 将接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化
5. 控制抽象
可以理解为传递的是一段逻辑, 一段代码
- 参数是函数
- 函数参数没有输入值也没有返回值
() => Unit
def myRunInThread(f1: () => Unit) = {
new Thread {
override def run(): Unit = {
f1()
}
}.start()
}
myRunInThread {
() =>
println("干活咯!5秒完成...")
Thread.sleep(5000)
println("干完咯!")
}
// 省略括号
def myRunInThread(f1: => Unit) = {
new Thread {
override def run(): Unit = {
f1()
}
}.start()
}
myRunInThread {
println("干活咯!5秒完成...")
Thread.sleep(5000)
println("干完咯!")
}
var x = 10
def until(condition: => Boolean)(block: => Unit): Unit = {
//类似while循环,递归
if (condition) {
block
until(condition)(block)
}
}
until(x > 0) {
x -= 1
println("x=" + x)
}
// 可以理解为: 参数有多行改用{}