/**
* 第6章 高阶函数
*/
//########################### 6.1 作为参数的函数 #################################
import scala.math._
/**
* scala中,函数可以作为参数进行传递
* 三中写法都可以
*/
def plus(x: Double) = 3 * x
Array(3.14, 1.42, 2.0).map(plus(_))
Array(3.14, 1.42, 2.0).map(plus _)
Array(3.14, 1.42, 2.0).map(plus)
/**
* 将函数赋值给变量fun
* 既然函数可以赋值到变量,那就该有类型,函数的类型为:(参数类型...)=>返回类型
* 如fun类型: Double => Double
*/
val num = 3.14
//将函数赋值给变量fun
val fun = ceil _
//相当于把ceil()函数赋值到变量fun2上
val fun2 = ceil(_)
fun(num)
//将函数传递
Array(3.14, 1.42, 2.0).map(fun)
//########################### 6.2 匿名函数 #################################
/**
* () {} 都可以
*/
Array(3.14, 1.42, 2.0).map((x: Double) => 3 * x)
Array(3.14, 1.42, 2.0).map { (x: Double) => 3 * x }
//########################### 6.3 高阶函数 #################################
/**
* 能够接受函数作为参数的函数,叫做高阶函数
*/
def valueAtOneQuarter(f: (Double) => Double) = f(0.25)
/**
* 高阶函数也可以返回函数
* mulBy的函数类型: (Double) => ((Double) => Double)
*/
def mulBy(factor: Double) = (x: Double) => factor * x
val quintuple = mulBy(5)
//等同于
val quintuple2 = (x: Double) => 5 * x
quintuple(10)
//########################### 6.4 参数(类型)推断 #################################
/**
* 匿名函数参数的类型推断
*/
//传入函数表达式
valueAtOneQuarter((x: Double) => 3 * x)
//参数推断省去类型信息
valueAtOneQuarter((x) => 3 * x)
//单个参数可以省去括号
valueAtOneQuarter(x => 3 * x)
//如果变量只在=>右边出现一次,可以用_来代替
valueAtOneQuarter(3 * _)
//########################### 6.5 闭包 #################################
/**
* 闭包就是一个函数把外部的那些不属于自己的对象也包含(闭包)进来了
* 匿名函数(x: Double) => factor * x 嵌套在函数mulBy中
* 匿名函数(x: Double) => factor * x 使用了外部变量(即mulBy的局部变量factory)
* mulBy2(3)时,triple将匿名函数的外部变量factor包了起来,形成一个"函数样板",因此trple、half这两个函数叫闭包
* 闭包函数由代码合代码用到的非局部变量定义构成
*/
def mulBy2(factor: Double) = (x: Double) => factor * x
val triple = mulBy2(3)
val half = mulBy2(0.5)
println(triple(14) + " " + half(14))
//########################### 6.6 柯里化 #################################
/**
* 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化
* 柯里化就是证明了函数只需要一个参数而已
*/
//传统定义2个参数
def mul(x: Int, y: Int) = x * y
mul(6, 7)
//柯里化定义,使用到闭包
def mulOneAtTime(x: Int) = (y: Int) => x * y
mulOneAtTime(6)(7)
//相当于下面
val sixBei = mulOneAtTime(6)
sixBei(7)
//Scala中可以简写,参数也可以是函数
def mulOneAtTime2(x: Int)(y: Int) = x * y
mulOneAtTime2(6)(7)
//不能写下面
//val sixBei2 = mulOneAtTime2(6)
//sixBei2(7)
//柯里化的应用
//比如2个数组在某一对比条件下的对等性
val a = Array("Hello", "World")
val b = Array("hello", "world")
//corresponds函数定义使用了柯里化
a.corresponds(b)(_.equalsIgnoreCase(_))
// def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = {...}
//########################### 6.7 控制抽象函数 #################################
/**
* 控制抽象是一类函数:
* 1、参数是函数
* 2、函数参数没有输入值,也没有返回值
*/
def runInThread(block: () => Unit): Unit = {
new Thread {
override def run() {
block()
}
}.start()
}
println("Thread.currentThread().getName = " + Thread.currentThread().getName)
//传入函数
runInThread { () => println(Thread.currentThread().getName); println("Hi"); Thread.sleep(3000); println("Bye") }
//上面是匿名函数作为参数传入的写法,多行表达式需要用{}括起来,之间需要用;隔开,等同于下面这样,将一个函数传入runInThread(函数)中
val fun3 = { () => println(Thread.currentThread().getName); println("Hi"); Thread.sleep(3000); println("Bye"); }
runInThread(fun3)
/**
* () => 有些多余,可以使用换名调用来表示,省略() 保留=>
* 这种叫控制抽象函数(看上去像是编程语言关键字的函数)
*/
def runInThread2(block: => Unit): Unit = {
new Thread {
override def run() {
block
}
}.start()
}
//优雅的传入
runInThread2 { println("Hi"); Thread.sleep(3000); println("Bye") }
/**
* 可以定义类似于while的until函数
* 可以看出,until其内部逻辑已定好,它就像一个关键字一样抽象地控制传入函数的执行,所以叫控制抽象
* 这里也用到了柯里化: def until(condition: => Boolean)(block: => Unit)
* 没有用到闭包,因为x不是until的局部变量,而是一个全局变量
*/
def until(condition: => Boolean)(block: => Unit) {
if (!condition) {
block
until(condition)(block)
}
}
var x = 10
//unitl (condition) {block}
until(x == 0) {x -= 1; println(x) }